@gbozee/ultimate 0.0.2-next.75 → 0.0.2-next.77
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 +200 -4
- package/dist/index.d.ts +96 -1
- package/dist/index.js +200 -4
- package/dist/mcp-server.cjs +198 -4
- package/dist/mcp-server.js +198 -4
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -67566,6 +67566,8 @@ class AppDatabase {
|
|
|
67566
67566
|
var exports_exchange_account = {};
|
|
67567
67567
|
__export(exports_exchange_account, {
|
|
67568
67568
|
getExchangeAccount: () => getExchangeAccount,
|
|
67569
|
+
TakeProfitReplaceRollbackSucceededError: () => TakeProfitReplaceRollbackSucceededError,
|
|
67570
|
+
TakeProfitReplaceRollbackFailedError: () => TakeProfitReplaceRollbackFailedError,
|
|
67569
67571
|
ExchangeAccount: () => ExchangeAccount
|
|
67570
67572
|
});
|
|
67571
67573
|
|
|
@@ -78395,6 +78397,76 @@ async function forceClosePosition2(client, symbol, options) {
|
|
|
78395
78397
|
}
|
|
78396
78398
|
|
|
78397
78399
|
// src/exchange-account.ts
|
|
78400
|
+
function getFormatPrecision(places) {
|
|
78401
|
+
if (!places) {
|
|
78402
|
+
return 0;
|
|
78403
|
+
}
|
|
78404
|
+
const match = places.match(/%\.(\d+)f/);
|
|
78405
|
+
return match ? Number(match[1]) : 0;
|
|
78406
|
+
}
|
|
78407
|
+
function floorToFormat(value2, places) {
|
|
78408
|
+
if (!Number.isFinite(value2) || value2 <= 0) {
|
|
78409
|
+
return 0;
|
|
78410
|
+
}
|
|
78411
|
+
const precision = getFormatPrecision(places);
|
|
78412
|
+
const factor = 10 ** precision;
|
|
78413
|
+
return Math.floor((value2 + Number.EPSILON) * factor) / factor;
|
|
78414
|
+
}
|
|
78415
|
+
|
|
78416
|
+
class TakeProfitReplaceRollbackSucceededError extends Error {
|
|
78417
|
+
status = "rollback_succeeded";
|
|
78418
|
+
restored = true;
|
|
78419
|
+
symbol;
|
|
78420
|
+
kind;
|
|
78421
|
+
takeProfitPrice;
|
|
78422
|
+
quantity;
|
|
78423
|
+
previousTakeProfitPrice;
|
|
78424
|
+
previousQuantity;
|
|
78425
|
+
restoreAttempted;
|
|
78426
|
+
cause;
|
|
78427
|
+
rollbackError;
|
|
78428
|
+
constructor(metadata3) {
|
|
78429
|
+
super("Take profit replacement failed and previous take profit was restored");
|
|
78430
|
+
this.name = "TakeProfitReplaceRollbackSucceededError";
|
|
78431
|
+
this.symbol = metadata3.symbol;
|
|
78432
|
+
this.kind = metadata3.kind;
|
|
78433
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
78434
|
+
this.quantity = metadata3.quantity;
|
|
78435
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
78436
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
78437
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
78438
|
+
this.cause = metadata3.cause;
|
|
78439
|
+
this.rollbackError = metadata3.rollbackError;
|
|
78440
|
+
}
|
|
78441
|
+
}
|
|
78442
|
+
|
|
78443
|
+
class TakeProfitReplaceRollbackFailedError extends Error {
|
|
78444
|
+
status = "rollback_failed";
|
|
78445
|
+
restored = false;
|
|
78446
|
+
symbol;
|
|
78447
|
+
kind;
|
|
78448
|
+
takeProfitPrice;
|
|
78449
|
+
quantity;
|
|
78450
|
+
previousTakeProfitPrice;
|
|
78451
|
+
previousQuantity;
|
|
78452
|
+
restoreAttempted;
|
|
78453
|
+
cause;
|
|
78454
|
+
rollbackError;
|
|
78455
|
+
constructor(metadata3) {
|
|
78456
|
+
super("Take profit replacement failed and previous take profit could not be restored");
|
|
78457
|
+
this.name = "TakeProfitReplaceRollbackFailedError";
|
|
78458
|
+
this.symbol = metadata3.symbol;
|
|
78459
|
+
this.kind = metadata3.kind;
|
|
78460
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
78461
|
+
this.quantity = metadata3.quantity;
|
|
78462
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
78463
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
78464
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
78465
|
+
this.cause = metadata3.cause;
|
|
78466
|
+
this.rollbackError = metadata3.rollbackError;
|
|
78467
|
+
}
|
|
78468
|
+
}
|
|
78469
|
+
|
|
78398
78470
|
class ExchangeAccount {
|
|
78399
78471
|
instance;
|
|
78400
78472
|
exchange;
|
|
@@ -78491,8 +78563,6 @@ class ExchangeAccount {
|
|
|
78491
78563
|
refresh
|
|
78492
78564
|
});
|
|
78493
78565
|
const raw_active_account = live_exchange_instance.data;
|
|
78494
|
-
console.log("raw_active", raw_active_account);
|
|
78495
|
-
console.log("symbol_config", symbol_config);
|
|
78496
78566
|
const _all = get_active_accounts({
|
|
78497
78567
|
active_account: raw_active_account,
|
|
78498
78568
|
symbol_config
|
|
@@ -78626,6 +78696,132 @@ class ExchangeAccount {
|
|
|
78626
78696
|
});
|
|
78627
78697
|
return await focus_position.cancelOrders(payload);
|
|
78628
78698
|
}
|
|
78699
|
+
async replaceTakeProfitForPosition(payload) {
|
|
78700
|
+
const { symbol, kind, takeProfitPrice, quantity } = payload;
|
|
78701
|
+
const focusPosition = await this.getFocusPosition({
|
|
78702
|
+
symbol,
|
|
78703
|
+
kind,
|
|
78704
|
+
update: true
|
|
78705
|
+
});
|
|
78706
|
+
const position2 = focusPosition.getInstance();
|
|
78707
|
+
const symbol_config = focusPosition.symbol_config;
|
|
78708
|
+
if (!symbol_config) {
|
|
78709
|
+
throw new Error(`Missing symbol config for ${symbol}`);
|
|
78710
|
+
}
|
|
78711
|
+
const normalizedQuantity = floorToFormat(quantity, symbol_config.decimal_places);
|
|
78712
|
+
const minSize = Number(symbol_config.min_size || 0);
|
|
78713
|
+
const previousTakeProfitPrice = Number(position2?.take_profit || 0);
|
|
78714
|
+
const previousQuantity = floorToFormat(Number(position2?.tp_quantity || 0), symbol_config.decimal_places);
|
|
78715
|
+
if (normalizedQuantity <= 0) {
|
|
78716
|
+
return {
|
|
78717
|
+
status: "below_min_lot",
|
|
78718
|
+
symbol,
|
|
78719
|
+
kind,
|
|
78720
|
+
takeProfitPrice,
|
|
78721
|
+
quantity: 0,
|
|
78722
|
+
minSize,
|
|
78723
|
+
reason: "quantity_floored_to_zero"
|
|
78724
|
+
};
|
|
78725
|
+
}
|
|
78726
|
+
if (minSize > 0 && normalizedQuantity < minSize) {
|
|
78727
|
+
return {
|
|
78728
|
+
status: "below_min_lot",
|
|
78729
|
+
symbol,
|
|
78730
|
+
kind,
|
|
78731
|
+
takeProfitPrice,
|
|
78732
|
+
quantity: normalizedQuantity,
|
|
78733
|
+
minSize,
|
|
78734
|
+
reason: "below_venue_minimum"
|
|
78735
|
+
};
|
|
78736
|
+
}
|
|
78737
|
+
const exchangeSeams = this.exchange;
|
|
78738
|
+
if (exchangeSeams.replaceTakeProfitForPosition) {
|
|
78739
|
+
await exchangeSeams.replaceTakeProfitForPosition({
|
|
78740
|
+
symbol,
|
|
78741
|
+
kind,
|
|
78742
|
+
takeProfitPrice,
|
|
78743
|
+
quantity: normalizedQuantity,
|
|
78744
|
+
price_places: symbol_config.price_places,
|
|
78745
|
+
decimal_places: symbol_config.decimal_places,
|
|
78746
|
+
previousTakeProfitPrice,
|
|
78747
|
+
previousQuantity
|
|
78748
|
+
});
|
|
78749
|
+
return {
|
|
78750
|
+
status: "replaced",
|
|
78751
|
+
symbol,
|
|
78752
|
+
kind,
|
|
78753
|
+
takeProfitPrice,
|
|
78754
|
+
quantity: normalizedQuantity,
|
|
78755
|
+
previousTakeProfitPrice,
|
|
78756
|
+
previousQuantity,
|
|
78757
|
+
restoreAttempted: false,
|
|
78758
|
+
via: "native_replace"
|
|
78759
|
+
};
|
|
78760
|
+
}
|
|
78761
|
+
const placeTpWithoutCancelling = exchangeSeams._placeTpOrder;
|
|
78762
|
+
if (!placeTpWithoutCancelling) {
|
|
78763
|
+
throw new Error(`Exchange ${this.instance.exchange} does not expose a TP replace or raw TP placement path`);
|
|
78764
|
+
}
|
|
78765
|
+
if (previousTakeProfitPrice > 0) {
|
|
78766
|
+
await this.cancelOrders({
|
|
78767
|
+
symbol,
|
|
78768
|
+
kind,
|
|
78769
|
+
price: previousTakeProfitPrice
|
|
78770
|
+
});
|
|
78771
|
+
}
|
|
78772
|
+
try {
|
|
78773
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
78774
|
+
symbol,
|
|
78775
|
+
tp: takeProfitPrice,
|
|
78776
|
+
kind,
|
|
78777
|
+
quantity: normalizedQuantity,
|
|
78778
|
+
cancel: false,
|
|
78779
|
+
price_places: symbol_config.price_places,
|
|
78780
|
+
decimal_places: symbol_config.decimal_places
|
|
78781
|
+
});
|
|
78782
|
+
return {
|
|
78783
|
+
status: "replaced",
|
|
78784
|
+
symbol,
|
|
78785
|
+
kind,
|
|
78786
|
+
takeProfitPrice,
|
|
78787
|
+
quantity: normalizedQuantity,
|
|
78788
|
+
previousTakeProfitPrice,
|
|
78789
|
+
previousQuantity,
|
|
78790
|
+
restoreAttempted: false
|
|
78791
|
+
};
|
|
78792
|
+
} catch (cause) {
|
|
78793
|
+
const metadata3 = {
|
|
78794
|
+
symbol,
|
|
78795
|
+
kind,
|
|
78796
|
+
takeProfitPrice,
|
|
78797
|
+
quantity: normalizedQuantity,
|
|
78798
|
+
previousTakeProfitPrice,
|
|
78799
|
+
previousQuantity,
|
|
78800
|
+
restoreAttempted: previousTakeProfitPrice > 0 && previousQuantity > 0,
|
|
78801
|
+
cause
|
|
78802
|
+
};
|
|
78803
|
+
if (!metadata3.restoreAttempted) {
|
|
78804
|
+
throw new TakeProfitReplaceRollbackFailedError(metadata3);
|
|
78805
|
+
}
|
|
78806
|
+
try {
|
|
78807
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
78808
|
+
symbol,
|
|
78809
|
+
tp: previousTakeProfitPrice,
|
|
78810
|
+
kind,
|
|
78811
|
+
quantity: previousQuantity,
|
|
78812
|
+
cancel: false,
|
|
78813
|
+
price_places: symbol_config.price_places,
|
|
78814
|
+
decimal_places: symbol_config.decimal_places
|
|
78815
|
+
});
|
|
78816
|
+
} catch (rollbackError) {
|
|
78817
|
+
throw new TakeProfitReplaceRollbackFailedError({
|
|
78818
|
+
...metadata3,
|
|
78819
|
+
rollbackError
|
|
78820
|
+
});
|
|
78821
|
+
}
|
|
78822
|
+
throw new TakeProfitReplaceRollbackSucceededError(metadata3);
|
|
78823
|
+
}
|
|
78824
|
+
}
|
|
78629
78825
|
async cancelExchangeOrders(payload) {
|
|
78630
78826
|
return this.exchange.cancelOrders(payload);
|
|
78631
78827
|
}
|
|
@@ -78910,8 +79106,8 @@ class ExchangeAccount {
|
|
|
78910
79106
|
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
78911
79107
|
return await this.reduceMajorPositionEntry({
|
|
78912
79108
|
symbol,
|
|
78913
|
-
long: config2.long,
|
|
78914
|
-
short: config2.short,
|
|
79109
|
+
long: kind === "long" ? config2.long : undefined,
|
|
79110
|
+
short: kind === "short" ? config2.short : undefined,
|
|
78915
79111
|
trigger: config2.trigger
|
|
78916
79112
|
});
|
|
78917
79113
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -7212,6 +7212,47 @@ export declare class ExchangePosition {
|
|
|
7212
7212
|
}, isIsolated?: boolean): Promise<void>;
|
|
7213
7213
|
buildMarginData(place?: boolean): Promise<any | null>;
|
|
7214
7214
|
}
|
|
7215
|
+
export type TakeProfitReplaceMetadata = {
|
|
7216
|
+
status: "rollback_succeeded" | "rollback_failed";
|
|
7217
|
+
restored: boolean;
|
|
7218
|
+
symbol: string;
|
|
7219
|
+
kind: "long" | "short";
|
|
7220
|
+
takeProfitPrice: number;
|
|
7221
|
+
quantity: number;
|
|
7222
|
+
previousTakeProfitPrice: number;
|
|
7223
|
+
previousQuantity: number;
|
|
7224
|
+
restoreAttempted: boolean;
|
|
7225
|
+
cause: unknown;
|
|
7226
|
+
rollbackError?: unknown;
|
|
7227
|
+
};
|
|
7228
|
+
declare class TakeProfitReplaceRollbackSucceededError extends Error implements TakeProfitReplaceMetadata {
|
|
7229
|
+
status: "rollback_succeeded";
|
|
7230
|
+
restored: true;
|
|
7231
|
+
symbol: string;
|
|
7232
|
+
kind: "long" | "short";
|
|
7233
|
+
takeProfitPrice: number;
|
|
7234
|
+
quantity: number;
|
|
7235
|
+
previousTakeProfitPrice: number;
|
|
7236
|
+
previousQuantity: number;
|
|
7237
|
+
restoreAttempted: boolean;
|
|
7238
|
+
cause: unknown;
|
|
7239
|
+
rollbackError?: unknown;
|
|
7240
|
+
constructor(metadata: Omit<TakeProfitReplaceMetadata, "status" | "restored">);
|
|
7241
|
+
}
|
|
7242
|
+
declare class TakeProfitReplaceRollbackFailedError extends Error implements TakeProfitReplaceMetadata {
|
|
7243
|
+
status: "rollback_failed";
|
|
7244
|
+
restored: false;
|
|
7245
|
+
symbol: string;
|
|
7246
|
+
kind: "long" | "short";
|
|
7247
|
+
takeProfitPrice: number;
|
|
7248
|
+
quantity: number;
|
|
7249
|
+
previousTakeProfitPrice: number;
|
|
7250
|
+
previousQuantity: number;
|
|
7251
|
+
restoreAttempted: boolean;
|
|
7252
|
+
cause: unknown;
|
|
7253
|
+
rollbackError?: unknown;
|
|
7254
|
+
constructor(metadata: Omit<TakeProfitReplaceMetadata, "status" | "restored">);
|
|
7255
|
+
}
|
|
7215
7256
|
declare class ExchangeAccount$1 {
|
|
7216
7257
|
instance: {
|
|
7217
7258
|
owner: string;
|
|
@@ -7398,6 +7439,60 @@ declare class ExchangeAccount$1 {
|
|
|
7398
7439
|
message?: undefined;
|
|
7399
7440
|
exchange_result?: undefined;
|
|
7400
7441
|
}>;
|
|
7442
|
+
replaceTakeProfitForPosition(payload: {
|
|
7443
|
+
symbol: string;
|
|
7444
|
+
kind: "long" | "short";
|
|
7445
|
+
takeProfitPrice: number;
|
|
7446
|
+
quantity: number;
|
|
7447
|
+
}): Promise<{
|
|
7448
|
+
status: "below_min_lot";
|
|
7449
|
+
symbol: string;
|
|
7450
|
+
kind: "long" | "short";
|
|
7451
|
+
takeProfitPrice: number;
|
|
7452
|
+
quantity: number;
|
|
7453
|
+
minSize: number;
|
|
7454
|
+
reason: "quantity_floored_to_zero";
|
|
7455
|
+
previousTakeProfitPrice?: undefined;
|
|
7456
|
+
previousQuantity?: undefined;
|
|
7457
|
+
restoreAttempted?: undefined;
|
|
7458
|
+
via?: undefined;
|
|
7459
|
+
} | {
|
|
7460
|
+
status: "below_min_lot";
|
|
7461
|
+
symbol: string;
|
|
7462
|
+
kind: "long" | "short";
|
|
7463
|
+
takeProfitPrice: number;
|
|
7464
|
+
quantity: number;
|
|
7465
|
+
minSize: number;
|
|
7466
|
+
reason: "below_venue_minimum";
|
|
7467
|
+
previousTakeProfitPrice?: undefined;
|
|
7468
|
+
previousQuantity?: undefined;
|
|
7469
|
+
restoreAttempted?: undefined;
|
|
7470
|
+
via?: undefined;
|
|
7471
|
+
} | {
|
|
7472
|
+
status: "replaced";
|
|
7473
|
+
symbol: string;
|
|
7474
|
+
kind: "long" | "short";
|
|
7475
|
+
takeProfitPrice: number;
|
|
7476
|
+
quantity: number;
|
|
7477
|
+
previousTakeProfitPrice: number;
|
|
7478
|
+
previousQuantity: number;
|
|
7479
|
+
restoreAttempted: boolean;
|
|
7480
|
+
via: "native_replace";
|
|
7481
|
+
minSize?: undefined;
|
|
7482
|
+
reason?: undefined;
|
|
7483
|
+
} | {
|
|
7484
|
+
status: "replaced";
|
|
7485
|
+
symbol: string;
|
|
7486
|
+
kind: "long" | "short";
|
|
7487
|
+
takeProfitPrice: number;
|
|
7488
|
+
quantity: number;
|
|
7489
|
+
previousTakeProfitPrice: number;
|
|
7490
|
+
previousQuantity: number;
|
|
7491
|
+
restoreAttempted: boolean;
|
|
7492
|
+
minSize?: undefined;
|
|
7493
|
+
reason?: undefined;
|
|
7494
|
+
via?: undefined;
|
|
7495
|
+
}>;
|
|
7401
7496
|
cancelExchangeOrders(payload: {
|
|
7402
7497
|
symbol: string;
|
|
7403
7498
|
orders: number[];
|
|
@@ -8327,7 +8422,7 @@ declare namespace database {
|
|
|
8327
8422
|
export { AppDatabase, ExchangeType, decryptObject, encryptObject, initPocketBaseClient };
|
|
8328
8423
|
}
|
|
8329
8424
|
declare namespace exchange_account {
|
|
8330
|
-
export { ExchangeAccount$1 as ExchangeAccount, getExchangeAccount };
|
|
8425
|
+
export { ExchangeAccount$1 as ExchangeAccount, TakeProfitReplaceRollbackFailedError, TakeProfitReplaceRollbackSucceededError, getExchangeAccount };
|
|
8331
8426
|
}
|
|
8332
8427
|
declare namespace app {
|
|
8333
8428
|
export { App, getCredentials, initApp, initialize };
|
package/dist/index.js
CHANGED
|
@@ -67464,6 +67464,8 @@ class AppDatabase {
|
|
|
67464
67464
|
var exports_exchange_account = {};
|
|
67465
67465
|
__export(exports_exchange_account, {
|
|
67466
67466
|
getExchangeAccount: () => getExchangeAccount,
|
|
67467
|
+
TakeProfitReplaceRollbackSucceededError: () => TakeProfitReplaceRollbackSucceededError,
|
|
67468
|
+
TakeProfitReplaceRollbackFailedError: () => TakeProfitReplaceRollbackFailedError,
|
|
67467
67469
|
ExchangeAccount: () => ExchangeAccount
|
|
67468
67470
|
});
|
|
67469
67471
|
|
|
@@ -78293,6 +78295,76 @@ async function forceClosePosition2(client, symbol, options) {
|
|
|
78293
78295
|
}
|
|
78294
78296
|
|
|
78295
78297
|
// src/exchange-account.ts
|
|
78298
|
+
function getFormatPrecision(places) {
|
|
78299
|
+
if (!places) {
|
|
78300
|
+
return 0;
|
|
78301
|
+
}
|
|
78302
|
+
const match = places.match(/%\.(\d+)f/);
|
|
78303
|
+
return match ? Number(match[1]) : 0;
|
|
78304
|
+
}
|
|
78305
|
+
function floorToFormat(value2, places) {
|
|
78306
|
+
if (!Number.isFinite(value2) || value2 <= 0) {
|
|
78307
|
+
return 0;
|
|
78308
|
+
}
|
|
78309
|
+
const precision = getFormatPrecision(places);
|
|
78310
|
+
const factor = 10 ** precision;
|
|
78311
|
+
return Math.floor((value2 + Number.EPSILON) * factor) / factor;
|
|
78312
|
+
}
|
|
78313
|
+
|
|
78314
|
+
class TakeProfitReplaceRollbackSucceededError extends Error {
|
|
78315
|
+
status = "rollback_succeeded";
|
|
78316
|
+
restored = true;
|
|
78317
|
+
symbol;
|
|
78318
|
+
kind;
|
|
78319
|
+
takeProfitPrice;
|
|
78320
|
+
quantity;
|
|
78321
|
+
previousTakeProfitPrice;
|
|
78322
|
+
previousQuantity;
|
|
78323
|
+
restoreAttempted;
|
|
78324
|
+
cause;
|
|
78325
|
+
rollbackError;
|
|
78326
|
+
constructor(metadata3) {
|
|
78327
|
+
super("Take profit replacement failed and previous take profit was restored");
|
|
78328
|
+
this.name = "TakeProfitReplaceRollbackSucceededError";
|
|
78329
|
+
this.symbol = metadata3.symbol;
|
|
78330
|
+
this.kind = metadata3.kind;
|
|
78331
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
78332
|
+
this.quantity = metadata3.quantity;
|
|
78333
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
78334
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
78335
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
78336
|
+
this.cause = metadata3.cause;
|
|
78337
|
+
this.rollbackError = metadata3.rollbackError;
|
|
78338
|
+
}
|
|
78339
|
+
}
|
|
78340
|
+
|
|
78341
|
+
class TakeProfitReplaceRollbackFailedError extends Error {
|
|
78342
|
+
status = "rollback_failed";
|
|
78343
|
+
restored = false;
|
|
78344
|
+
symbol;
|
|
78345
|
+
kind;
|
|
78346
|
+
takeProfitPrice;
|
|
78347
|
+
quantity;
|
|
78348
|
+
previousTakeProfitPrice;
|
|
78349
|
+
previousQuantity;
|
|
78350
|
+
restoreAttempted;
|
|
78351
|
+
cause;
|
|
78352
|
+
rollbackError;
|
|
78353
|
+
constructor(metadata3) {
|
|
78354
|
+
super("Take profit replacement failed and previous take profit could not be restored");
|
|
78355
|
+
this.name = "TakeProfitReplaceRollbackFailedError";
|
|
78356
|
+
this.symbol = metadata3.symbol;
|
|
78357
|
+
this.kind = metadata3.kind;
|
|
78358
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
78359
|
+
this.quantity = metadata3.quantity;
|
|
78360
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
78361
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
78362
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
78363
|
+
this.cause = metadata3.cause;
|
|
78364
|
+
this.rollbackError = metadata3.rollbackError;
|
|
78365
|
+
}
|
|
78366
|
+
}
|
|
78367
|
+
|
|
78296
78368
|
class ExchangeAccount {
|
|
78297
78369
|
instance;
|
|
78298
78370
|
exchange;
|
|
@@ -78389,8 +78461,6 @@ class ExchangeAccount {
|
|
|
78389
78461
|
refresh
|
|
78390
78462
|
});
|
|
78391
78463
|
const raw_active_account = live_exchange_instance.data;
|
|
78392
|
-
console.log("raw_active", raw_active_account);
|
|
78393
|
-
console.log("symbol_config", symbol_config);
|
|
78394
78464
|
const _all = get_active_accounts({
|
|
78395
78465
|
active_account: raw_active_account,
|
|
78396
78466
|
symbol_config
|
|
@@ -78524,6 +78594,132 @@ class ExchangeAccount {
|
|
|
78524
78594
|
});
|
|
78525
78595
|
return await focus_position.cancelOrders(payload);
|
|
78526
78596
|
}
|
|
78597
|
+
async replaceTakeProfitForPosition(payload) {
|
|
78598
|
+
const { symbol, kind, takeProfitPrice, quantity } = payload;
|
|
78599
|
+
const focusPosition = await this.getFocusPosition({
|
|
78600
|
+
symbol,
|
|
78601
|
+
kind,
|
|
78602
|
+
update: true
|
|
78603
|
+
});
|
|
78604
|
+
const position2 = focusPosition.getInstance();
|
|
78605
|
+
const symbol_config = focusPosition.symbol_config;
|
|
78606
|
+
if (!symbol_config) {
|
|
78607
|
+
throw new Error(`Missing symbol config for ${symbol}`);
|
|
78608
|
+
}
|
|
78609
|
+
const normalizedQuantity = floorToFormat(quantity, symbol_config.decimal_places);
|
|
78610
|
+
const minSize = Number(symbol_config.min_size || 0);
|
|
78611
|
+
const previousTakeProfitPrice = Number(position2?.take_profit || 0);
|
|
78612
|
+
const previousQuantity = floorToFormat(Number(position2?.tp_quantity || 0), symbol_config.decimal_places);
|
|
78613
|
+
if (normalizedQuantity <= 0) {
|
|
78614
|
+
return {
|
|
78615
|
+
status: "below_min_lot",
|
|
78616
|
+
symbol,
|
|
78617
|
+
kind,
|
|
78618
|
+
takeProfitPrice,
|
|
78619
|
+
quantity: 0,
|
|
78620
|
+
minSize,
|
|
78621
|
+
reason: "quantity_floored_to_zero"
|
|
78622
|
+
};
|
|
78623
|
+
}
|
|
78624
|
+
if (minSize > 0 && normalizedQuantity < minSize) {
|
|
78625
|
+
return {
|
|
78626
|
+
status: "below_min_lot",
|
|
78627
|
+
symbol,
|
|
78628
|
+
kind,
|
|
78629
|
+
takeProfitPrice,
|
|
78630
|
+
quantity: normalizedQuantity,
|
|
78631
|
+
minSize,
|
|
78632
|
+
reason: "below_venue_minimum"
|
|
78633
|
+
};
|
|
78634
|
+
}
|
|
78635
|
+
const exchangeSeams = this.exchange;
|
|
78636
|
+
if (exchangeSeams.replaceTakeProfitForPosition) {
|
|
78637
|
+
await exchangeSeams.replaceTakeProfitForPosition({
|
|
78638
|
+
symbol,
|
|
78639
|
+
kind,
|
|
78640
|
+
takeProfitPrice,
|
|
78641
|
+
quantity: normalizedQuantity,
|
|
78642
|
+
price_places: symbol_config.price_places,
|
|
78643
|
+
decimal_places: symbol_config.decimal_places,
|
|
78644
|
+
previousTakeProfitPrice,
|
|
78645
|
+
previousQuantity
|
|
78646
|
+
});
|
|
78647
|
+
return {
|
|
78648
|
+
status: "replaced",
|
|
78649
|
+
symbol,
|
|
78650
|
+
kind,
|
|
78651
|
+
takeProfitPrice,
|
|
78652
|
+
quantity: normalizedQuantity,
|
|
78653
|
+
previousTakeProfitPrice,
|
|
78654
|
+
previousQuantity,
|
|
78655
|
+
restoreAttempted: false,
|
|
78656
|
+
via: "native_replace"
|
|
78657
|
+
};
|
|
78658
|
+
}
|
|
78659
|
+
const placeTpWithoutCancelling = exchangeSeams._placeTpOrder;
|
|
78660
|
+
if (!placeTpWithoutCancelling) {
|
|
78661
|
+
throw new Error(`Exchange ${this.instance.exchange} does not expose a TP replace or raw TP placement path`);
|
|
78662
|
+
}
|
|
78663
|
+
if (previousTakeProfitPrice > 0) {
|
|
78664
|
+
await this.cancelOrders({
|
|
78665
|
+
symbol,
|
|
78666
|
+
kind,
|
|
78667
|
+
price: previousTakeProfitPrice
|
|
78668
|
+
});
|
|
78669
|
+
}
|
|
78670
|
+
try {
|
|
78671
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
78672
|
+
symbol,
|
|
78673
|
+
tp: takeProfitPrice,
|
|
78674
|
+
kind,
|
|
78675
|
+
quantity: normalizedQuantity,
|
|
78676
|
+
cancel: false,
|
|
78677
|
+
price_places: symbol_config.price_places,
|
|
78678
|
+
decimal_places: symbol_config.decimal_places
|
|
78679
|
+
});
|
|
78680
|
+
return {
|
|
78681
|
+
status: "replaced",
|
|
78682
|
+
symbol,
|
|
78683
|
+
kind,
|
|
78684
|
+
takeProfitPrice,
|
|
78685
|
+
quantity: normalizedQuantity,
|
|
78686
|
+
previousTakeProfitPrice,
|
|
78687
|
+
previousQuantity,
|
|
78688
|
+
restoreAttempted: false
|
|
78689
|
+
};
|
|
78690
|
+
} catch (cause) {
|
|
78691
|
+
const metadata3 = {
|
|
78692
|
+
symbol,
|
|
78693
|
+
kind,
|
|
78694
|
+
takeProfitPrice,
|
|
78695
|
+
quantity: normalizedQuantity,
|
|
78696
|
+
previousTakeProfitPrice,
|
|
78697
|
+
previousQuantity,
|
|
78698
|
+
restoreAttempted: previousTakeProfitPrice > 0 && previousQuantity > 0,
|
|
78699
|
+
cause
|
|
78700
|
+
};
|
|
78701
|
+
if (!metadata3.restoreAttempted) {
|
|
78702
|
+
throw new TakeProfitReplaceRollbackFailedError(metadata3);
|
|
78703
|
+
}
|
|
78704
|
+
try {
|
|
78705
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
78706
|
+
symbol,
|
|
78707
|
+
tp: previousTakeProfitPrice,
|
|
78708
|
+
kind,
|
|
78709
|
+
quantity: previousQuantity,
|
|
78710
|
+
cancel: false,
|
|
78711
|
+
price_places: symbol_config.price_places,
|
|
78712
|
+
decimal_places: symbol_config.decimal_places
|
|
78713
|
+
});
|
|
78714
|
+
} catch (rollbackError) {
|
|
78715
|
+
throw new TakeProfitReplaceRollbackFailedError({
|
|
78716
|
+
...metadata3,
|
|
78717
|
+
rollbackError
|
|
78718
|
+
});
|
|
78719
|
+
}
|
|
78720
|
+
throw new TakeProfitReplaceRollbackSucceededError(metadata3);
|
|
78721
|
+
}
|
|
78722
|
+
}
|
|
78527
78723
|
async cancelExchangeOrders(payload) {
|
|
78528
78724
|
return this.exchange.cancelOrders(payload);
|
|
78529
78725
|
}
|
|
@@ -78808,8 +79004,8 @@ class ExchangeAccount {
|
|
|
78808
79004
|
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
78809
79005
|
return await this.reduceMajorPositionEntry({
|
|
78810
79006
|
symbol,
|
|
78811
|
-
long: config2.long,
|
|
78812
|
-
short: config2.short,
|
|
79007
|
+
long: kind === "long" ? config2.long : undefined,
|
|
79008
|
+
short: kind === "short" ? config2.short : undefined,
|
|
78813
79009
|
trigger: config2.trigger
|
|
78814
79010
|
});
|
|
78815
79011
|
}
|
package/dist/mcp-server.cjs
CHANGED
|
@@ -82117,6 +82117,76 @@ async function forceClosePosition2(client, symbol, options) {
|
|
|
82117
82117
|
}
|
|
82118
82118
|
|
|
82119
82119
|
// src/exchange-account.ts
|
|
82120
|
+
function getFormatPrecision(places) {
|
|
82121
|
+
if (!places) {
|
|
82122
|
+
return 0;
|
|
82123
|
+
}
|
|
82124
|
+
const match = places.match(/%\.(\d+)f/);
|
|
82125
|
+
return match ? Number(match[1]) : 0;
|
|
82126
|
+
}
|
|
82127
|
+
function floorToFormat(value2, places) {
|
|
82128
|
+
if (!Number.isFinite(value2) || value2 <= 0) {
|
|
82129
|
+
return 0;
|
|
82130
|
+
}
|
|
82131
|
+
const precision = getFormatPrecision(places);
|
|
82132
|
+
const factor = 10 ** precision;
|
|
82133
|
+
return Math.floor((value2 + Number.EPSILON) * factor) / factor;
|
|
82134
|
+
}
|
|
82135
|
+
|
|
82136
|
+
class TakeProfitReplaceRollbackSucceededError extends Error {
|
|
82137
|
+
status = "rollback_succeeded";
|
|
82138
|
+
restored = true;
|
|
82139
|
+
symbol;
|
|
82140
|
+
kind;
|
|
82141
|
+
takeProfitPrice;
|
|
82142
|
+
quantity;
|
|
82143
|
+
previousTakeProfitPrice;
|
|
82144
|
+
previousQuantity;
|
|
82145
|
+
restoreAttempted;
|
|
82146
|
+
cause;
|
|
82147
|
+
rollbackError;
|
|
82148
|
+
constructor(metadata3) {
|
|
82149
|
+
super("Take profit replacement failed and previous take profit was restored");
|
|
82150
|
+
this.name = "TakeProfitReplaceRollbackSucceededError";
|
|
82151
|
+
this.symbol = metadata3.symbol;
|
|
82152
|
+
this.kind = metadata3.kind;
|
|
82153
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82154
|
+
this.quantity = metadata3.quantity;
|
|
82155
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82156
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82157
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82158
|
+
this.cause = metadata3.cause;
|
|
82159
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82160
|
+
}
|
|
82161
|
+
}
|
|
82162
|
+
|
|
82163
|
+
class TakeProfitReplaceRollbackFailedError extends Error {
|
|
82164
|
+
status = "rollback_failed";
|
|
82165
|
+
restored = false;
|
|
82166
|
+
symbol;
|
|
82167
|
+
kind;
|
|
82168
|
+
takeProfitPrice;
|
|
82169
|
+
quantity;
|
|
82170
|
+
previousTakeProfitPrice;
|
|
82171
|
+
previousQuantity;
|
|
82172
|
+
restoreAttempted;
|
|
82173
|
+
cause;
|
|
82174
|
+
rollbackError;
|
|
82175
|
+
constructor(metadata3) {
|
|
82176
|
+
super("Take profit replacement failed and previous take profit could not be restored");
|
|
82177
|
+
this.name = "TakeProfitReplaceRollbackFailedError";
|
|
82178
|
+
this.symbol = metadata3.symbol;
|
|
82179
|
+
this.kind = metadata3.kind;
|
|
82180
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82181
|
+
this.quantity = metadata3.quantity;
|
|
82182
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82183
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82184
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82185
|
+
this.cause = metadata3.cause;
|
|
82186
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82187
|
+
}
|
|
82188
|
+
}
|
|
82189
|
+
|
|
82120
82190
|
class ExchangeAccount {
|
|
82121
82191
|
instance;
|
|
82122
82192
|
exchange;
|
|
@@ -82213,8 +82283,6 @@ class ExchangeAccount {
|
|
|
82213
82283
|
refresh
|
|
82214
82284
|
});
|
|
82215
82285
|
const raw_active_account = live_exchange_instance.data;
|
|
82216
|
-
console.log("raw_active", raw_active_account);
|
|
82217
|
-
console.log("symbol_config", symbol_config);
|
|
82218
82286
|
const _all = get_active_accounts({
|
|
82219
82287
|
active_account: raw_active_account,
|
|
82220
82288
|
symbol_config
|
|
@@ -82348,6 +82416,132 @@ class ExchangeAccount {
|
|
|
82348
82416
|
});
|
|
82349
82417
|
return await focus_position.cancelOrders(payload);
|
|
82350
82418
|
}
|
|
82419
|
+
async replaceTakeProfitForPosition(payload) {
|
|
82420
|
+
const { symbol, kind, takeProfitPrice, quantity } = payload;
|
|
82421
|
+
const focusPosition = await this.getFocusPosition({
|
|
82422
|
+
symbol,
|
|
82423
|
+
kind,
|
|
82424
|
+
update: true
|
|
82425
|
+
});
|
|
82426
|
+
const position2 = focusPosition.getInstance();
|
|
82427
|
+
const symbol_config = focusPosition.symbol_config;
|
|
82428
|
+
if (!symbol_config) {
|
|
82429
|
+
throw new Error(`Missing symbol config for ${symbol}`);
|
|
82430
|
+
}
|
|
82431
|
+
const normalizedQuantity = floorToFormat(quantity, symbol_config.decimal_places);
|
|
82432
|
+
const minSize = Number(symbol_config.min_size || 0);
|
|
82433
|
+
const previousTakeProfitPrice = Number(position2?.take_profit || 0);
|
|
82434
|
+
const previousQuantity = floorToFormat(Number(position2?.tp_quantity || 0), symbol_config.decimal_places);
|
|
82435
|
+
if (normalizedQuantity <= 0) {
|
|
82436
|
+
return {
|
|
82437
|
+
status: "below_min_lot",
|
|
82438
|
+
symbol,
|
|
82439
|
+
kind,
|
|
82440
|
+
takeProfitPrice,
|
|
82441
|
+
quantity: 0,
|
|
82442
|
+
minSize,
|
|
82443
|
+
reason: "quantity_floored_to_zero"
|
|
82444
|
+
};
|
|
82445
|
+
}
|
|
82446
|
+
if (minSize > 0 && normalizedQuantity < minSize) {
|
|
82447
|
+
return {
|
|
82448
|
+
status: "below_min_lot",
|
|
82449
|
+
symbol,
|
|
82450
|
+
kind,
|
|
82451
|
+
takeProfitPrice,
|
|
82452
|
+
quantity: normalizedQuantity,
|
|
82453
|
+
minSize,
|
|
82454
|
+
reason: "below_venue_minimum"
|
|
82455
|
+
};
|
|
82456
|
+
}
|
|
82457
|
+
const exchangeSeams = this.exchange;
|
|
82458
|
+
if (exchangeSeams.replaceTakeProfitForPosition) {
|
|
82459
|
+
await exchangeSeams.replaceTakeProfitForPosition({
|
|
82460
|
+
symbol,
|
|
82461
|
+
kind,
|
|
82462
|
+
takeProfitPrice,
|
|
82463
|
+
quantity: normalizedQuantity,
|
|
82464
|
+
price_places: symbol_config.price_places,
|
|
82465
|
+
decimal_places: symbol_config.decimal_places,
|
|
82466
|
+
previousTakeProfitPrice,
|
|
82467
|
+
previousQuantity
|
|
82468
|
+
});
|
|
82469
|
+
return {
|
|
82470
|
+
status: "replaced",
|
|
82471
|
+
symbol,
|
|
82472
|
+
kind,
|
|
82473
|
+
takeProfitPrice,
|
|
82474
|
+
quantity: normalizedQuantity,
|
|
82475
|
+
previousTakeProfitPrice,
|
|
82476
|
+
previousQuantity,
|
|
82477
|
+
restoreAttempted: false,
|
|
82478
|
+
via: "native_replace"
|
|
82479
|
+
};
|
|
82480
|
+
}
|
|
82481
|
+
const placeTpWithoutCancelling = exchangeSeams._placeTpOrder;
|
|
82482
|
+
if (!placeTpWithoutCancelling) {
|
|
82483
|
+
throw new Error(`Exchange ${this.instance.exchange} does not expose a TP replace or raw TP placement path`);
|
|
82484
|
+
}
|
|
82485
|
+
if (previousTakeProfitPrice > 0) {
|
|
82486
|
+
await this.cancelOrders({
|
|
82487
|
+
symbol,
|
|
82488
|
+
kind,
|
|
82489
|
+
price: previousTakeProfitPrice
|
|
82490
|
+
});
|
|
82491
|
+
}
|
|
82492
|
+
try {
|
|
82493
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82494
|
+
symbol,
|
|
82495
|
+
tp: takeProfitPrice,
|
|
82496
|
+
kind,
|
|
82497
|
+
quantity: normalizedQuantity,
|
|
82498
|
+
cancel: false,
|
|
82499
|
+
price_places: symbol_config.price_places,
|
|
82500
|
+
decimal_places: symbol_config.decimal_places
|
|
82501
|
+
});
|
|
82502
|
+
return {
|
|
82503
|
+
status: "replaced",
|
|
82504
|
+
symbol,
|
|
82505
|
+
kind,
|
|
82506
|
+
takeProfitPrice,
|
|
82507
|
+
quantity: normalizedQuantity,
|
|
82508
|
+
previousTakeProfitPrice,
|
|
82509
|
+
previousQuantity,
|
|
82510
|
+
restoreAttempted: false
|
|
82511
|
+
};
|
|
82512
|
+
} catch (cause) {
|
|
82513
|
+
const metadata3 = {
|
|
82514
|
+
symbol,
|
|
82515
|
+
kind,
|
|
82516
|
+
takeProfitPrice,
|
|
82517
|
+
quantity: normalizedQuantity,
|
|
82518
|
+
previousTakeProfitPrice,
|
|
82519
|
+
previousQuantity,
|
|
82520
|
+
restoreAttempted: previousTakeProfitPrice > 0 && previousQuantity > 0,
|
|
82521
|
+
cause
|
|
82522
|
+
};
|
|
82523
|
+
if (!metadata3.restoreAttempted) {
|
|
82524
|
+
throw new TakeProfitReplaceRollbackFailedError(metadata3);
|
|
82525
|
+
}
|
|
82526
|
+
try {
|
|
82527
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82528
|
+
symbol,
|
|
82529
|
+
tp: previousTakeProfitPrice,
|
|
82530
|
+
kind,
|
|
82531
|
+
quantity: previousQuantity,
|
|
82532
|
+
cancel: false,
|
|
82533
|
+
price_places: symbol_config.price_places,
|
|
82534
|
+
decimal_places: symbol_config.decimal_places
|
|
82535
|
+
});
|
|
82536
|
+
} catch (rollbackError) {
|
|
82537
|
+
throw new TakeProfitReplaceRollbackFailedError({
|
|
82538
|
+
...metadata3,
|
|
82539
|
+
rollbackError
|
|
82540
|
+
});
|
|
82541
|
+
}
|
|
82542
|
+
throw new TakeProfitReplaceRollbackSucceededError(metadata3);
|
|
82543
|
+
}
|
|
82544
|
+
}
|
|
82351
82545
|
async cancelExchangeOrders(payload) {
|
|
82352
82546
|
return this.exchange.cancelOrders(payload);
|
|
82353
82547
|
}
|
|
@@ -82632,8 +82826,8 @@ class ExchangeAccount {
|
|
|
82632
82826
|
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
82633
82827
|
return await this.reduceMajorPositionEntry({
|
|
82634
82828
|
symbol,
|
|
82635
|
-
long: config2.long,
|
|
82636
|
-
short: config2.short,
|
|
82829
|
+
long: kind === "long" ? config2.long : undefined,
|
|
82830
|
+
short: kind === "short" ? config2.short : undefined,
|
|
82637
82831
|
trigger: config2.trigger
|
|
82638
82832
|
});
|
|
82639
82833
|
}
|
package/dist/mcp-server.js
CHANGED
|
@@ -82076,6 +82076,76 @@ async function forceClosePosition2(client, symbol, options) {
|
|
|
82076
82076
|
}
|
|
82077
82077
|
|
|
82078
82078
|
// src/exchange-account.ts
|
|
82079
|
+
function getFormatPrecision(places) {
|
|
82080
|
+
if (!places) {
|
|
82081
|
+
return 0;
|
|
82082
|
+
}
|
|
82083
|
+
const match = places.match(/%\.(\d+)f/);
|
|
82084
|
+
return match ? Number(match[1]) : 0;
|
|
82085
|
+
}
|
|
82086
|
+
function floorToFormat(value2, places) {
|
|
82087
|
+
if (!Number.isFinite(value2) || value2 <= 0) {
|
|
82088
|
+
return 0;
|
|
82089
|
+
}
|
|
82090
|
+
const precision = getFormatPrecision(places);
|
|
82091
|
+
const factor = 10 ** precision;
|
|
82092
|
+
return Math.floor((value2 + Number.EPSILON) * factor) / factor;
|
|
82093
|
+
}
|
|
82094
|
+
|
|
82095
|
+
class TakeProfitReplaceRollbackSucceededError extends Error {
|
|
82096
|
+
status = "rollback_succeeded";
|
|
82097
|
+
restored = true;
|
|
82098
|
+
symbol;
|
|
82099
|
+
kind;
|
|
82100
|
+
takeProfitPrice;
|
|
82101
|
+
quantity;
|
|
82102
|
+
previousTakeProfitPrice;
|
|
82103
|
+
previousQuantity;
|
|
82104
|
+
restoreAttempted;
|
|
82105
|
+
cause;
|
|
82106
|
+
rollbackError;
|
|
82107
|
+
constructor(metadata3) {
|
|
82108
|
+
super("Take profit replacement failed and previous take profit was restored");
|
|
82109
|
+
this.name = "TakeProfitReplaceRollbackSucceededError";
|
|
82110
|
+
this.symbol = metadata3.symbol;
|
|
82111
|
+
this.kind = metadata3.kind;
|
|
82112
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82113
|
+
this.quantity = metadata3.quantity;
|
|
82114
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82115
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82116
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82117
|
+
this.cause = metadata3.cause;
|
|
82118
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82119
|
+
}
|
|
82120
|
+
}
|
|
82121
|
+
|
|
82122
|
+
class TakeProfitReplaceRollbackFailedError extends Error {
|
|
82123
|
+
status = "rollback_failed";
|
|
82124
|
+
restored = false;
|
|
82125
|
+
symbol;
|
|
82126
|
+
kind;
|
|
82127
|
+
takeProfitPrice;
|
|
82128
|
+
quantity;
|
|
82129
|
+
previousTakeProfitPrice;
|
|
82130
|
+
previousQuantity;
|
|
82131
|
+
restoreAttempted;
|
|
82132
|
+
cause;
|
|
82133
|
+
rollbackError;
|
|
82134
|
+
constructor(metadata3) {
|
|
82135
|
+
super("Take profit replacement failed and previous take profit could not be restored");
|
|
82136
|
+
this.name = "TakeProfitReplaceRollbackFailedError";
|
|
82137
|
+
this.symbol = metadata3.symbol;
|
|
82138
|
+
this.kind = metadata3.kind;
|
|
82139
|
+
this.takeProfitPrice = metadata3.takeProfitPrice;
|
|
82140
|
+
this.quantity = metadata3.quantity;
|
|
82141
|
+
this.previousTakeProfitPrice = metadata3.previousTakeProfitPrice;
|
|
82142
|
+
this.previousQuantity = metadata3.previousQuantity;
|
|
82143
|
+
this.restoreAttempted = metadata3.restoreAttempted;
|
|
82144
|
+
this.cause = metadata3.cause;
|
|
82145
|
+
this.rollbackError = metadata3.rollbackError;
|
|
82146
|
+
}
|
|
82147
|
+
}
|
|
82148
|
+
|
|
82079
82149
|
class ExchangeAccount {
|
|
82080
82150
|
instance;
|
|
82081
82151
|
exchange;
|
|
@@ -82172,8 +82242,6 @@ class ExchangeAccount {
|
|
|
82172
82242
|
refresh
|
|
82173
82243
|
});
|
|
82174
82244
|
const raw_active_account = live_exchange_instance.data;
|
|
82175
|
-
console.log("raw_active", raw_active_account);
|
|
82176
|
-
console.log("symbol_config", symbol_config);
|
|
82177
82245
|
const _all = get_active_accounts({
|
|
82178
82246
|
active_account: raw_active_account,
|
|
82179
82247
|
symbol_config
|
|
@@ -82307,6 +82375,132 @@ class ExchangeAccount {
|
|
|
82307
82375
|
});
|
|
82308
82376
|
return await focus_position.cancelOrders(payload);
|
|
82309
82377
|
}
|
|
82378
|
+
async replaceTakeProfitForPosition(payload) {
|
|
82379
|
+
const { symbol, kind, takeProfitPrice, quantity } = payload;
|
|
82380
|
+
const focusPosition = await this.getFocusPosition({
|
|
82381
|
+
symbol,
|
|
82382
|
+
kind,
|
|
82383
|
+
update: true
|
|
82384
|
+
});
|
|
82385
|
+
const position2 = focusPosition.getInstance();
|
|
82386
|
+
const symbol_config = focusPosition.symbol_config;
|
|
82387
|
+
if (!symbol_config) {
|
|
82388
|
+
throw new Error(`Missing symbol config for ${symbol}`);
|
|
82389
|
+
}
|
|
82390
|
+
const normalizedQuantity = floorToFormat(quantity, symbol_config.decimal_places);
|
|
82391
|
+
const minSize = Number(symbol_config.min_size || 0);
|
|
82392
|
+
const previousTakeProfitPrice = Number(position2?.take_profit || 0);
|
|
82393
|
+
const previousQuantity = floorToFormat(Number(position2?.tp_quantity || 0), symbol_config.decimal_places);
|
|
82394
|
+
if (normalizedQuantity <= 0) {
|
|
82395
|
+
return {
|
|
82396
|
+
status: "below_min_lot",
|
|
82397
|
+
symbol,
|
|
82398
|
+
kind,
|
|
82399
|
+
takeProfitPrice,
|
|
82400
|
+
quantity: 0,
|
|
82401
|
+
minSize,
|
|
82402
|
+
reason: "quantity_floored_to_zero"
|
|
82403
|
+
};
|
|
82404
|
+
}
|
|
82405
|
+
if (minSize > 0 && normalizedQuantity < minSize) {
|
|
82406
|
+
return {
|
|
82407
|
+
status: "below_min_lot",
|
|
82408
|
+
symbol,
|
|
82409
|
+
kind,
|
|
82410
|
+
takeProfitPrice,
|
|
82411
|
+
quantity: normalizedQuantity,
|
|
82412
|
+
minSize,
|
|
82413
|
+
reason: "below_venue_minimum"
|
|
82414
|
+
};
|
|
82415
|
+
}
|
|
82416
|
+
const exchangeSeams = this.exchange;
|
|
82417
|
+
if (exchangeSeams.replaceTakeProfitForPosition) {
|
|
82418
|
+
await exchangeSeams.replaceTakeProfitForPosition({
|
|
82419
|
+
symbol,
|
|
82420
|
+
kind,
|
|
82421
|
+
takeProfitPrice,
|
|
82422
|
+
quantity: normalizedQuantity,
|
|
82423
|
+
price_places: symbol_config.price_places,
|
|
82424
|
+
decimal_places: symbol_config.decimal_places,
|
|
82425
|
+
previousTakeProfitPrice,
|
|
82426
|
+
previousQuantity
|
|
82427
|
+
});
|
|
82428
|
+
return {
|
|
82429
|
+
status: "replaced",
|
|
82430
|
+
symbol,
|
|
82431
|
+
kind,
|
|
82432
|
+
takeProfitPrice,
|
|
82433
|
+
quantity: normalizedQuantity,
|
|
82434
|
+
previousTakeProfitPrice,
|
|
82435
|
+
previousQuantity,
|
|
82436
|
+
restoreAttempted: false,
|
|
82437
|
+
via: "native_replace"
|
|
82438
|
+
};
|
|
82439
|
+
}
|
|
82440
|
+
const placeTpWithoutCancelling = exchangeSeams._placeTpOrder;
|
|
82441
|
+
if (!placeTpWithoutCancelling) {
|
|
82442
|
+
throw new Error(`Exchange ${this.instance.exchange} does not expose a TP replace or raw TP placement path`);
|
|
82443
|
+
}
|
|
82444
|
+
if (previousTakeProfitPrice > 0) {
|
|
82445
|
+
await this.cancelOrders({
|
|
82446
|
+
symbol,
|
|
82447
|
+
kind,
|
|
82448
|
+
price: previousTakeProfitPrice
|
|
82449
|
+
});
|
|
82450
|
+
}
|
|
82451
|
+
try {
|
|
82452
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82453
|
+
symbol,
|
|
82454
|
+
tp: takeProfitPrice,
|
|
82455
|
+
kind,
|
|
82456
|
+
quantity: normalizedQuantity,
|
|
82457
|
+
cancel: false,
|
|
82458
|
+
price_places: symbol_config.price_places,
|
|
82459
|
+
decimal_places: symbol_config.decimal_places
|
|
82460
|
+
});
|
|
82461
|
+
return {
|
|
82462
|
+
status: "replaced",
|
|
82463
|
+
symbol,
|
|
82464
|
+
kind,
|
|
82465
|
+
takeProfitPrice,
|
|
82466
|
+
quantity: normalizedQuantity,
|
|
82467
|
+
previousTakeProfitPrice,
|
|
82468
|
+
previousQuantity,
|
|
82469
|
+
restoreAttempted: false
|
|
82470
|
+
};
|
|
82471
|
+
} catch (cause) {
|
|
82472
|
+
const metadata3 = {
|
|
82473
|
+
symbol,
|
|
82474
|
+
kind,
|
|
82475
|
+
takeProfitPrice,
|
|
82476
|
+
quantity: normalizedQuantity,
|
|
82477
|
+
previousTakeProfitPrice,
|
|
82478
|
+
previousQuantity,
|
|
82479
|
+
restoreAttempted: previousTakeProfitPrice > 0 && previousQuantity > 0,
|
|
82480
|
+
cause
|
|
82481
|
+
};
|
|
82482
|
+
if (!metadata3.restoreAttempted) {
|
|
82483
|
+
throw new TakeProfitReplaceRollbackFailedError(metadata3);
|
|
82484
|
+
}
|
|
82485
|
+
try {
|
|
82486
|
+
await placeTpWithoutCancelling.call(this.exchange, {
|
|
82487
|
+
symbol,
|
|
82488
|
+
tp: previousTakeProfitPrice,
|
|
82489
|
+
kind,
|
|
82490
|
+
quantity: previousQuantity,
|
|
82491
|
+
cancel: false,
|
|
82492
|
+
price_places: symbol_config.price_places,
|
|
82493
|
+
decimal_places: symbol_config.decimal_places
|
|
82494
|
+
});
|
|
82495
|
+
} catch (rollbackError) {
|
|
82496
|
+
throw new TakeProfitReplaceRollbackFailedError({
|
|
82497
|
+
...metadata3,
|
|
82498
|
+
rollbackError
|
|
82499
|
+
});
|
|
82500
|
+
}
|
|
82501
|
+
throw new TakeProfitReplaceRollbackSucceededError(metadata3);
|
|
82502
|
+
}
|
|
82503
|
+
}
|
|
82310
82504
|
async cancelExchangeOrders(payload) {
|
|
82311
82505
|
return this.exchange.cancelOrders(payload);
|
|
82312
82506
|
}
|
|
@@ -82591,8 +82785,8 @@ class ExchangeAccount {
|
|
|
82591
82785
|
if (payload.trigger && !long_pause_tp && !short_pause_tp && config2) {
|
|
82592
82786
|
return await this.reduceMajorPositionEntry({
|
|
82593
82787
|
symbol,
|
|
82594
|
-
long: config2.long,
|
|
82595
|
-
short: config2.short,
|
|
82788
|
+
long: kind === "long" ? config2.long : undefined,
|
|
82789
|
+
short: kind === "short" ? config2.short : undefined,
|
|
82596
82790
|
trigger: config2.trigger
|
|
82597
82791
|
});
|
|
82598
82792
|
}
|