@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 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
  }
@@ -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
  }
@@ -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
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gbozee/ultimate",
3
3
  "type": "module",
4
- "version": "0.0.2-next.75",
4
+ "version": "0.0.2-next.77",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",