backtest-kit 1.2.2 → 1.3.0

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/build/index.cjs CHANGED
@@ -131,12 +131,14 @@ const globalServices$1 = {
131
131
  exchangeGlobalService: Symbol('exchangeGlobalService'),
132
132
  strategyGlobalService: Symbol('strategyGlobalService'),
133
133
  frameGlobalService: Symbol('frameGlobalService'),
134
- liveGlobalService: Symbol('liveGlobalService'),
135
- backtestGlobalService: Symbol('backtestGlobalService'),
136
- walkerGlobalService: Symbol('walkerGlobalService'),
137
134
  sizingGlobalService: Symbol('sizingGlobalService'),
138
135
  riskGlobalService: Symbol('riskGlobalService'),
139
136
  };
137
+ const commandServices$1 = {
138
+ liveCommandService: Symbol('liveCommandService'),
139
+ backtestCommandService: Symbol('backtestCommandService'),
140
+ walkerCommandService: Symbol('walkerCommandService'),
141
+ };
140
142
  const logicPrivateServices$1 = {
141
143
  backtestLogicPrivateService: Symbol('backtestLogicPrivateService'),
142
144
  liveLogicPrivateService: Symbol('liveLogicPrivateService'),
@@ -169,6 +171,7 @@ const TYPES = {
169
171
  ...connectionServices$1,
170
172
  ...schemaServices$1,
171
173
  ...globalServices$1,
174
+ ...commandServices$1,
172
175
  ...logicPrivateServices$1,
173
176
  ...logicPublicServices$1,
174
177
  ...markdownServices$1,
@@ -1457,8 +1460,15 @@ const INTERVAL_MINUTES$1 = {
1457
1460
  "30m": 30,
1458
1461
  "1h": 60,
1459
1462
  };
1460
- const VALIDATE_SIGNAL_FN = (signal) => {
1463
+ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
1461
1464
  const errors = [];
1465
+ // ЗАЩИТА ОТ NaN/Infinity: currentPrice должна быть конечным числом
1466
+ if (!isFinite(currentPrice)) {
1467
+ errors.push(`currentPrice must be a finite number, got ${currentPrice} (${typeof currentPrice})`);
1468
+ }
1469
+ if (isFinite(currentPrice) && currentPrice <= 0) {
1470
+ errors.push(`currentPrice must be positive, got ${currentPrice}`);
1471
+ }
1462
1472
  // ЗАЩИТА ОТ NaN/Infinity: все цены должны быть конечными числами
1463
1473
  if (!isFinite(signal.priceOpen)) {
1464
1474
  errors.push(`priceOpen must be a finite number, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
@@ -1487,6 +1497,20 @@ const VALIDATE_SIGNAL_FN = (signal) => {
1487
1497
  if (signal.priceStopLoss >= signal.priceOpen) {
1488
1498
  errors.push(`Long: priceStopLoss (${signal.priceStopLoss}) must be < priceOpen (${signal.priceOpen})`);
1489
1499
  }
1500
+ // ЗАЩИТА ОТ EDGE CASE: для immediate сигналов проверяем что текущая цена не пробила SL/TP
1501
+ // Для scheduled сигналов эта проверка избыточна т.к. priceOpen уже проверен выше
1502
+ if (!isScheduled) {
1503
+ // Текущая цена уже пробила StopLoss - позиция откроется и сразу закроется по SL
1504
+ if (isFinite(currentPrice) && currentPrice < signal.priceStopLoss) {
1505
+ errors.push(`Long: currentPrice (${currentPrice}) < priceStopLoss (${signal.priceStopLoss}). ` +
1506
+ `Signal would be immediately cancelled. This signal is invalid.`);
1507
+ }
1508
+ // Текущая цена уже достигла TakeProfit - профит упущен
1509
+ if (isFinite(currentPrice) && currentPrice > signal.priceTakeProfit) {
1510
+ errors.push(`Long: currentPrice (${currentPrice}) > priceTakeProfit (${signal.priceTakeProfit}). ` +
1511
+ `Signal is invalid - the profit opportunity has already passed.`);
1512
+ }
1513
+ }
1490
1514
  // ЗАЩИТА ОТ МИКРО-ПРОФИТА: TakeProfit должен быть достаточно далеко, чтобы покрыть комиссии
1491
1515
  if (GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
1492
1516
  const tpDistancePercent = ((signal.priceTakeProfit - signal.priceOpen) / signal.priceOpen) * 100;
@@ -1514,6 +1538,20 @@ const VALIDATE_SIGNAL_FN = (signal) => {
1514
1538
  if (signal.priceStopLoss <= signal.priceOpen) {
1515
1539
  errors.push(`Short: priceStopLoss (${signal.priceStopLoss}) must be > priceOpen (${signal.priceOpen})`);
1516
1540
  }
1541
+ // ЗАЩИТА ОТ EDGE CASE: для immediate сигналов проверяем что текущая цена не пробила SL/TP
1542
+ // Для scheduled сигналов эта проверка избыточна т.к. priceOpen уже проверен выше
1543
+ if (!isScheduled) {
1544
+ // Текущая цена уже пробила StopLoss - позиция откроется и сразу закроется по SL
1545
+ if (isFinite(currentPrice) && currentPrice > signal.priceStopLoss) {
1546
+ errors.push(`Short: currentPrice (${currentPrice}) > priceStopLoss (${signal.priceStopLoss}). ` +
1547
+ `Signal would be immediately cancelled. This signal is invalid.`);
1548
+ }
1549
+ // Текущая цена уже достигла TakeProfit - профит упущен
1550
+ if (isFinite(currentPrice) && currentPrice < signal.priceTakeProfit) {
1551
+ errors.push(`Short: currentPrice (${currentPrice}) < priceTakeProfit (${signal.priceTakeProfit}). ` +
1552
+ `Signal is invalid - the profit opportunity has already passed.`);
1553
+ }
1554
+ }
1517
1555
  // ЗАЩИТА ОТ МИКРО-ПРОФИТА: TakeProfit должен быть достаточно далеко, чтобы покрыть комиссии
1518
1556
  if (GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
1519
1557
  const tpDistancePercent = ((signal.priceOpen - signal.priceTakeProfit) / signal.priceOpen) * 100;
@@ -1587,8 +1625,36 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
1587
1625
  if (!signal) {
1588
1626
  return null;
1589
1627
  }
1590
- // Если priceOpen указан - создаем scheduled signal (risk check при активации)
1628
+ // Если priceOpen указан - проверяем нужно ли ждать активации или открыть сразу
1591
1629
  if (signal.priceOpen !== undefined) {
1630
+ // КРИТИЧЕСКАЯ ПРОВЕРКА: достигнут ли priceOpen?
1631
+ // LONG: если currentPrice <= priceOpen - цена уже упала достаточно, открываем сразу
1632
+ // SHORT: если currentPrice >= priceOpen - цена уже выросла достаточно, открываем сразу
1633
+ const shouldActivateImmediately = (signal.position === "long" && currentPrice <= signal.priceOpen) ||
1634
+ (signal.position === "short" && currentPrice >= signal.priceOpen);
1635
+ if (shouldActivateImmediately) {
1636
+ // НЕМЕДЛЕННАЯ АКТИВАЦИЯ: priceOpen уже достигнут
1637
+ // Создаем активный сигнал напрямую (БЕЗ scheduled фазы)
1638
+ const signalRow = {
1639
+ id: functoolsKit.randomString(),
1640
+ priceOpen: signal.priceOpen, // Используем priceOpen из сигнала
1641
+ position: signal.position,
1642
+ note: signal.note,
1643
+ priceTakeProfit: signal.priceTakeProfit,
1644
+ priceStopLoss: signal.priceStopLoss,
1645
+ minuteEstimatedTime: signal.minuteEstimatedTime,
1646
+ symbol: self.params.execution.context.symbol,
1647
+ exchangeName: self.params.method.context.exchangeName,
1648
+ strategyName: self.params.method.context.strategyName,
1649
+ scheduledAt: currentTime,
1650
+ pendingAt: currentTime, // Для immediate signal оба времени одинаковые
1651
+ _isScheduled: false,
1652
+ };
1653
+ // Валидируем сигнал перед возвратом
1654
+ VALIDATE_SIGNAL_FN(signalRow, currentPrice, false);
1655
+ return signalRow;
1656
+ }
1657
+ // ОЖИДАНИЕ АКТИВАЦИИ: создаем scheduled signal (risk check при активации)
1592
1658
  const scheduledSignalRow = {
1593
1659
  id: functoolsKit.randomString(),
1594
1660
  priceOpen: signal.priceOpen,
@@ -1605,7 +1671,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
1605
1671
  _isScheduled: true,
1606
1672
  };
1607
1673
  // Валидируем сигнал перед возвратом
1608
- VALIDATE_SIGNAL_FN(scheduledSignalRow);
1674
+ VALIDATE_SIGNAL_FN(scheduledSignalRow, currentPrice, true);
1609
1675
  return scheduledSignalRow;
1610
1676
  }
1611
1677
  const signalRow = {
@@ -1620,7 +1686,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
1620
1686
  _isScheduled: false,
1621
1687
  };
1622
1688
  // Валидируем сигнал перед возвратом
1623
- VALIDATE_SIGNAL_FN(signalRow);
1689
+ VALIDATE_SIGNAL_FN(signalRow, currentPrice, false);
1624
1690
  return signalRow;
1625
1691
  }, {
1626
1692
  defaultValue: null,
@@ -4795,14 +4861,14 @@ class WalkerLogicPublicService {
4795
4861
  }
4796
4862
  }
4797
4863
 
4798
- const METHOD_NAME_RUN$2 = "liveGlobalService run";
4864
+ const METHOD_NAME_RUN$2 = "liveCommandService run";
4799
4865
  /**
4800
4866
  * Global service providing access to live trading functionality.
4801
4867
  *
4802
4868
  * Simple wrapper around LiveLogicPublicService for dependency injection.
4803
4869
  * Used by public API exports.
4804
4870
  */
4805
- class LiveGlobalService {
4871
+ class LiveCommandService {
4806
4872
  constructor() {
4807
4873
  this.loggerService = inject(TYPES.loggerService);
4808
4874
  this.liveLogicPublicService = inject(TYPES.liveLogicPublicService);
@@ -4839,14 +4905,14 @@ class LiveGlobalService {
4839
4905
  }
4840
4906
  }
4841
4907
 
4842
- const METHOD_NAME_RUN$1 = "backtestGlobalService run";
4908
+ const METHOD_NAME_RUN$1 = "backtestCommandService run";
4843
4909
  /**
4844
4910
  * Global service providing access to backtest functionality.
4845
4911
  *
4846
4912
  * Simple wrapper around BacktestLogicPublicService for dependency injection.
4847
4913
  * Used by public API exports.
4848
4914
  */
4849
- class BacktestGlobalService {
4915
+ class BacktestCommandService {
4850
4916
  constructor() {
4851
4917
  this.loggerService = inject(TYPES.loggerService);
4852
4918
  this.strategySchemaService = inject(TYPES.strategySchemaService);
@@ -4882,14 +4948,14 @@ class BacktestGlobalService {
4882
4948
  }
4883
4949
  }
4884
4950
 
4885
- const METHOD_NAME_RUN = "walkerGlobalService run";
4951
+ const METHOD_NAME_RUN = "walkerCommandService run";
4886
4952
  /**
4887
4953
  * Global service providing access to walker functionality.
4888
4954
  *
4889
4955
  * Simple wrapper around WalkerLogicPublicService for dependency injection.
4890
4956
  * Used by public API exports.
4891
4957
  */
4892
- class WalkerGlobalService {
4958
+ class WalkerCommandService {
4893
4959
  constructor() {
4894
4960
  this.loggerService = inject(TYPES.loggerService);
4895
4961
  this.walkerLogicPublicService = inject(TYPES.walkerLogicPublicService);
@@ -7764,12 +7830,14 @@ class RiskValidationService {
7764
7830
  provide(TYPES.exchangeGlobalService, () => new ExchangeGlobalService());
7765
7831
  provide(TYPES.strategyGlobalService, () => new StrategyGlobalService());
7766
7832
  provide(TYPES.frameGlobalService, () => new FrameGlobalService());
7767
- provide(TYPES.liveGlobalService, () => new LiveGlobalService());
7768
- provide(TYPES.backtestGlobalService, () => new BacktestGlobalService());
7769
- provide(TYPES.walkerGlobalService, () => new WalkerGlobalService());
7770
7833
  provide(TYPES.sizingGlobalService, () => new SizingGlobalService());
7771
7834
  provide(TYPES.riskGlobalService, () => new RiskGlobalService());
7772
7835
  }
7836
+ {
7837
+ provide(TYPES.liveCommandService, () => new LiveCommandService());
7838
+ provide(TYPES.backtestCommandService, () => new BacktestCommandService());
7839
+ provide(TYPES.walkerCommandService, () => new WalkerCommandService());
7840
+ }
7773
7841
  {
7774
7842
  provide(TYPES.backtestLogicPrivateService, () => new BacktestLogicPrivateService());
7775
7843
  provide(TYPES.liveLogicPrivateService, () => new LiveLogicPrivateService());
@@ -7823,12 +7891,14 @@ const globalServices = {
7823
7891
  exchangeGlobalService: inject(TYPES.exchangeGlobalService),
7824
7892
  strategyGlobalService: inject(TYPES.strategyGlobalService),
7825
7893
  frameGlobalService: inject(TYPES.frameGlobalService),
7826
- liveGlobalService: inject(TYPES.liveGlobalService),
7827
- backtestGlobalService: inject(TYPES.backtestGlobalService),
7828
- walkerGlobalService: inject(TYPES.walkerGlobalService),
7829
7894
  sizingGlobalService: inject(TYPES.sizingGlobalService),
7830
7895
  riskGlobalService: inject(TYPES.riskGlobalService),
7831
7896
  };
7897
+ const commandServices = {
7898
+ liveCommandService: inject(TYPES.liveCommandService),
7899
+ backtestCommandService: inject(TYPES.backtestCommandService),
7900
+ walkerCommandService: inject(TYPES.walkerCommandService),
7901
+ };
7832
7902
  const logicPrivateServices = {
7833
7903
  backtestLogicPrivateService: inject(TYPES.backtestLogicPrivateService),
7834
7904
  liveLogicPrivateService: inject(TYPES.liveLogicPrivateService),
@@ -7861,6 +7931,7 @@ const backtest = {
7861
7931
  ...connectionServices,
7862
7932
  ...schemaServices,
7863
7933
  ...globalServices,
7934
+ ...commandServices,
7864
7935
  ...logicPrivateServices,
7865
7936
  ...logicPublicServices,
7866
7937
  ...markdownServices,
@@ -9155,7 +9226,7 @@ const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
9155
9226
  /**
9156
9227
  * Utility class for backtest operations.
9157
9228
  *
9158
- * Provides simplified access to backtestGlobalService.run() with logging.
9229
+ * Provides simplified access to backtestCommandService.run() with logging.
9159
9230
  * Exported as singleton instance for convenient usage.
9160
9231
  *
9161
9232
  * @example
@@ -9196,7 +9267,7 @@ class BacktestUtils {
9196
9267
  const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
9197
9268
  riskName && backtest$1.riskGlobalService.clear(riskName);
9198
9269
  }
9199
- return backtest$1.backtestGlobalService.run(symbol, context);
9270
+ return backtest$1.backtestCommandService.run(symbol, context);
9200
9271
  };
9201
9272
  /**
9202
9273
  * Runs backtest in background without yielding results.
@@ -9331,7 +9402,7 @@ const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
9331
9402
  /**
9332
9403
  * Utility class for live trading operations.
9333
9404
  *
9334
- * Provides simplified access to liveGlobalService.run() with logging.
9405
+ * Provides simplified access to liveCommandService.run() with logging.
9335
9406
  * Exported as singleton instance for convenient usage.
9336
9407
  *
9337
9408
  * Features:
@@ -9385,7 +9456,7 @@ class LiveUtils {
9385
9456
  const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
9386
9457
  riskName && backtest$1.riskGlobalService.clear(riskName);
9387
9458
  }
9388
- return backtest$1.liveGlobalService.run(symbol, context);
9459
+ return backtest$1.liveCommandService.run(symbol, context);
9389
9460
  };
9390
9461
  /**
9391
9462
  * Runs live trading in background without yielding results.
@@ -9771,7 +9842,7 @@ const WALKER_METHOD_NAME_DUMP = "WalkerUtils.dump";
9771
9842
  /**
9772
9843
  * Utility class for walker operations.
9773
9844
  *
9774
- * Provides simplified access to walkerGlobalService.run() with logging.
9845
+ * Provides simplified access to walkerCommandService.run() with logging.
9775
9846
  * Automatically pulls exchangeName and frameName from walker schema.
9776
9847
  * Exported as singleton instance for convenient usage.
9777
9848
  *
@@ -9823,7 +9894,7 @@ class WalkerUtils {
9823
9894
  riskName && backtest$1.riskGlobalService.clear(riskName);
9824
9895
  }
9825
9896
  }
9826
- return backtest$1.walkerGlobalService.run(symbol, {
9897
+ return backtest$1.walkerCommandService.run(symbol, {
9827
9898
  walkerName: context.walkerName,
9828
9899
  exchangeName: walkerSchema.exchangeName,
9829
9900
  frameName: walkerSchema.frameName,
package/build/index.mjs CHANGED
@@ -129,12 +129,14 @@ const globalServices$1 = {
129
129
  exchangeGlobalService: Symbol('exchangeGlobalService'),
130
130
  strategyGlobalService: Symbol('strategyGlobalService'),
131
131
  frameGlobalService: Symbol('frameGlobalService'),
132
- liveGlobalService: Symbol('liveGlobalService'),
133
- backtestGlobalService: Symbol('backtestGlobalService'),
134
- walkerGlobalService: Symbol('walkerGlobalService'),
135
132
  sizingGlobalService: Symbol('sizingGlobalService'),
136
133
  riskGlobalService: Symbol('riskGlobalService'),
137
134
  };
135
+ const commandServices$1 = {
136
+ liveCommandService: Symbol('liveCommandService'),
137
+ backtestCommandService: Symbol('backtestCommandService'),
138
+ walkerCommandService: Symbol('walkerCommandService'),
139
+ };
138
140
  const logicPrivateServices$1 = {
139
141
  backtestLogicPrivateService: Symbol('backtestLogicPrivateService'),
140
142
  liveLogicPrivateService: Symbol('liveLogicPrivateService'),
@@ -167,6 +169,7 @@ const TYPES = {
167
169
  ...connectionServices$1,
168
170
  ...schemaServices$1,
169
171
  ...globalServices$1,
172
+ ...commandServices$1,
170
173
  ...logicPrivateServices$1,
171
174
  ...logicPublicServices$1,
172
175
  ...markdownServices$1,
@@ -1455,8 +1458,15 @@ const INTERVAL_MINUTES$1 = {
1455
1458
  "30m": 30,
1456
1459
  "1h": 60,
1457
1460
  };
1458
- const VALIDATE_SIGNAL_FN = (signal) => {
1461
+ const VALIDATE_SIGNAL_FN = (signal, currentPrice, isScheduled) => {
1459
1462
  const errors = [];
1463
+ // ЗАЩИТА ОТ NaN/Infinity: currentPrice должна быть конечным числом
1464
+ if (!isFinite(currentPrice)) {
1465
+ errors.push(`currentPrice must be a finite number, got ${currentPrice} (${typeof currentPrice})`);
1466
+ }
1467
+ if (isFinite(currentPrice) && currentPrice <= 0) {
1468
+ errors.push(`currentPrice must be positive, got ${currentPrice}`);
1469
+ }
1460
1470
  // ЗАЩИТА ОТ NaN/Infinity: все цены должны быть конечными числами
1461
1471
  if (!isFinite(signal.priceOpen)) {
1462
1472
  errors.push(`priceOpen must be a finite number, got ${signal.priceOpen} (${typeof signal.priceOpen})`);
@@ -1485,6 +1495,20 @@ const VALIDATE_SIGNAL_FN = (signal) => {
1485
1495
  if (signal.priceStopLoss >= signal.priceOpen) {
1486
1496
  errors.push(`Long: priceStopLoss (${signal.priceStopLoss}) must be < priceOpen (${signal.priceOpen})`);
1487
1497
  }
1498
+ // ЗАЩИТА ОТ EDGE CASE: для immediate сигналов проверяем что текущая цена не пробила SL/TP
1499
+ // Для scheduled сигналов эта проверка избыточна т.к. priceOpen уже проверен выше
1500
+ if (!isScheduled) {
1501
+ // Текущая цена уже пробила StopLoss - позиция откроется и сразу закроется по SL
1502
+ if (isFinite(currentPrice) && currentPrice < signal.priceStopLoss) {
1503
+ errors.push(`Long: currentPrice (${currentPrice}) < priceStopLoss (${signal.priceStopLoss}). ` +
1504
+ `Signal would be immediately cancelled. This signal is invalid.`);
1505
+ }
1506
+ // Текущая цена уже достигла TakeProfit - профит упущен
1507
+ if (isFinite(currentPrice) && currentPrice > signal.priceTakeProfit) {
1508
+ errors.push(`Long: currentPrice (${currentPrice}) > priceTakeProfit (${signal.priceTakeProfit}). ` +
1509
+ `Signal is invalid - the profit opportunity has already passed.`);
1510
+ }
1511
+ }
1488
1512
  // ЗАЩИТА ОТ МИКРО-ПРОФИТА: TakeProfit должен быть достаточно далеко, чтобы покрыть комиссии
1489
1513
  if (GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
1490
1514
  const tpDistancePercent = ((signal.priceTakeProfit - signal.priceOpen) / signal.priceOpen) * 100;
@@ -1512,6 +1536,20 @@ const VALIDATE_SIGNAL_FN = (signal) => {
1512
1536
  if (signal.priceStopLoss <= signal.priceOpen) {
1513
1537
  errors.push(`Short: priceStopLoss (${signal.priceStopLoss}) must be > priceOpen (${signal.priceOpen})`);
1514
1538
  }
1539
+ // ЗАЩИТА ОТ EDGE CASE: для immediate сигналов проверяем что текущая цена не пробила SL/TP
1540
+ // Для scheduled сигналов эта проверка избыточна т.к. priceOpen уже проверен выше
1541
+ if (!isScheduled) {
1542
+ // Текущая цена уже пробила StopLoss - позиция откроется и сразу закроется по SL
1543
+ if (isFinite(currentPrice) && currentPrice > signal.priceStopLoss) {
1544
+ errors.push(`Short: currentPrice (${currentPrice}) > priceStopLoss (${signal.priceStopLoss}). ` +
1545
+ `Signal would be immediately cancelled. This signal is invalid.`);
1546
+ }
1547
+ // Текущая цена уже достигла TakeProfit - профит упущен
1548
+ if (isFinite(currentPrice) && currentPrice < signal.priceTakeProfit) {
1549
+ errors.push(`Short: currentPrice (${currentPrice}) < priceTakeProfit (${signal.priceTakeProfit}). ` +
1550
+ `Signal is invalid - the profit opportunity has already passed.`);
1551
+ }
1552
+ }
1515
1553
  // ЗАЩИТА ОТ МИКРО-ПРОФИТА: TakeProfit должен быть достаточно далеко, чтобы покрыть комиссии
1516
1554
  if (GLOBAL_CONFIG.CC_MIN_TAKEPROFIT_DISTANCE_PERCENT) {
1517
1555
  const tpDistancePercent = ((signal.priceOpen - signal.priceTakeProfit) / signal.priceOpen) * 100;
@@ -1585,8 +1623,36 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
1585
1623
  if (!signal) {
1586
1624
  return null;
1587
1625
  }
1588
- // Если priceOpen указан - создаем scheduled signal (risk check при активации)
1626
+ // Если priceOpen указан - проверяем нужно ли ждать активации или открыть сразу
1589
1627
  if (signal.priceOpen !== undefined) {
1628
+ // КРИТИЧЕСКАЯ ПРОВЕРКА: достигнут ли priceOpen?
1629
+ // LONG: если currentPrice <= priceOpen - цена уже упала достаточно, открываем сразу
1630
+ // SHORT: если currentPrice >= priceOpen - цена уже выросла достаточно, открываем сразу
1631
+ const shouldActivateImmediately = (signal.position === "long" && currentPrice <= signal.priceOpen) ||
1632
+ (signal.position === "short" && currentPrice >= signal.priceOpen);
1633
+ if (shouldActivateImmediately) {
1634
+ // НЕМЕДЛЕННАЯ АКТИВАЦИЯ: priceOpen уже достигнут
1635
+ // Создаем активный сигнал напрямую (БЕЗ scheduled фазы)
1636
+ const signalRow = {
1637
+ id: randomString(),
1638
+ priceOpen: signal.priceOpen, // Используем priceOpen из сигнала
1639
+ position: signal.position,
1640
+ note: signal.note,
1641
+ priceTakeProfit: signal.priceTakeProfit,
1642
+ priceStopLoss: signal.priceStopLoss,
1643
+ minuteEstimatedTime: signal.minuteEstimatedTime,
1644
+ symbol: self.params.execution.context.symbol,
1645
+ exchangeName: self.params.method.context.exchangeName,
1646
+ strategyName: self.params.method.context.strategyName,
1647
+ scheduledAt: currentTime,
1648
+ pendingAt: currentTime, // Для immediate signal оба времени одинаковые
1649
+ _isScheduled: false,
1650
+ };
1651
+ // Валидируем сигнал перед возвратом
1652
+ VALIDATE_SIGNAL_FN(signalRow, currentPrice, false);
1653
+ return signalRow;
1654
+ }
1655
+ // ОЖИДАНИЕ АКТИВАЦИИ: создаем scheduled signal (risk check при активации)
1590
1656
  const scheduledSignalRow = {
1591
1657
  id: randomString(),
1592
1658
  priceOpen: signal.priceOpen,
@@ -1603,7 +1669,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
1603
1669
  _isScheduled: true,
1604
1670
  };
1605
1671
  // Валидируем сигнал перед возвратом
1606
- VALIDATE_SIGNAL_FN(scheduledSignalRow);
1672
+ VALIDATE_SIGNAL_FN(scheduledSignalRow, currentPrice, true);
1607
1673
  return scheduledSignalRow;
1608
1674
  }
1609
1675
  const signalRow = {
@@ -1618,7 +1684,7 @@ const GET_SIGNAL_FN = trycatch(async (self) => {
1618
1684
  _isScheduled: false,
1619
1685
  };
1620
1686
  // Валидируем сигнал перед возвратом
1621
- VALIDATE_SIGNAL_FN(signalRow);
1687
+ VALIDATE_SIGNAL_FN(signalRow, currentPrice, false);
1622
1688
  return signalRow;
1623
1689
  }, {
1624
1690
  defaultValue: null,
@@ -4793,14 +4859,14 @@ class WalkerLogicPublicService {
4793
4859
  }
4794
4860
  }
4795
4861
 
4796
- const METHOD_NAME_RUN$2 = "liveGlobalService run";
4862
+ const METHOD_NAME_RUN$2 = "liveCommandService run";
4797
4863
  /**
4798
4864
  * Global service providing access to live trading functionality.
4799
4865
  *
4800
4866
  * Simple wrapper around LiveLogicPublicService for dependency injection.
4801
4867
  * Used by public API exports.
4802
4868
  */
4803
- class LiveGlobalService {
4869
+ class LiveCommandService {
4804
4870
  constructor() {
4805
4871
  this.loggerService = inject(TYPES.loggerService);
4806
4872
  this.liveLogicPublicService = inject(TYPES.liveLogicPublicService);
@@ -4837,14 +4903,14 @@ class LiveGlobalService {
4837
4903
  }
4838
4904
  }
4839
4905
 
4840
- const METHOD_NAME_RUN$1 = "backtestGlobalService run";
4906
+ const METHOD_NAME_RUN$1 = "backtestCommandService run";
4841
4907
  /**
4842
4908
  * Global service providing access to backtest functionality.
4843
4909
  *
4844
4910
  * Simple wrapper around BacktestLogicPublicService for dependency injection.
4845
4911
  * Used by public API exports.
4846
4912
  */
4847
- class BacktestGlobalService {
4913
+ class BacktestCommandService {
4848
4914
  constructor() {
4849
4915
  this.loggerService = inject(TYPES.loggerService);
4850
4916
  this.strategySchemaService = inject(TYPES.strategySchemaService);
@@ -4880,14 +4946,14 @@ class BacktestGlobalService {
4880
4946
  }
4881
4947
  }
4882
4948
 
4883
- const METHOD_NAME_RUN = "walkerGlobalService run";
4949
+ const METHOD_NAME_RUN = "walkerCommandService run";
4884
4950
  /**
4885
4951
  * Global service providing access to walker functionality.
4886
4952
  *
4887
4953
  * Simple wrapper around WalkerLogicPublicService for dependency injection.
4888
4954
  * Used by public API exports.
4889
4955
  */
4890
- class WalkerGlobalService {
4956
+ class WalkerCommandService {
4891
4957
  constructor() {
4892
4958
  this.loggerService = inject(TYPES.loggerService);
4893
4959
  this.walkerLogicPublicService = inject(TYPES.walkerLogicPublicService);
@@ -7762,12 +7828,14 @@ class RiskValidationService {
7762
7828
  provide(TYPES.exchangeGlobalService, () => new ExchangeGlobalService());
7763
7829
  provide(TYPES.strategyGlobalService, () => new StrategyGlobalService());
7764
7830
  provide(TYPES.frameGlobalService, () => new FrameGlobalService());
7765
- provide(TYPES.liveGlobalService, () => new LiveGlobalService());
7766
- provide(TYPES.backtestGlobalService, () => new BacktestGlobalService());
7767
- provide(TYPES.walkerGlobalService, () => new WalkerGlobalService());
7768
7831
  provide(TYPES.sizingGlobalService, () => new SizingGlobalService());
7769
7832
  provide(TYPES.riskGlobalService, () => new RiskGlobalService());
7770
7833
  }
7834
+ {
7835
+ provide(TYPES.liveCommandService, () => new LiveCommandService());
7836
+ provide(TYPES.backtestCommandService, () => new BacktestCommandService());
7837
+ provide(TYPES.walkerCommandService, () => new WalkerCommandService());
7838
+ }
7771
7839
  {
7772
7840
  provide(TYPES.backtestLogicPrivateService, () => new BacktestLogicPrivateService());
7773
7841
  provide(TYPES.liveLogicPrivateService, () => new LiveLogicPrivateService());
@@ -7821,12 +7889,14 @@ const globalServices = {
7821
7889
  exchangeGlobalService: inject(TYPES.exchangeGlobalService),
7822
7890
  strategyGlobalService: inject(TYPES.strategyGlobalService),
7823
7891
  frameGlobalService: inject(TYPES.frameGlobalService),
7824
- liveGlobalService: inject(TYPES.liveGlobalService),
7825
- backtestGlobalService: inject(TYPES.backtestGlobalService),
7826
- walkerGlobalService: inject(TYPES.walkerGlobalService),
7827
7892
  sizingGlobalService: inject(TYPES.sizingGlobalService),
7828
7893
  riskGlobalService: inject(TYPES.riskGlobalService),
7829
7894
  };
7895
+ const commandServices = {
7896
+ liveCommandService: inject(TYPES.liveCommandService),
7897
+ backtestCommandService: inject(TYPES.backtestCommandService),
7898
+ walkerCommandService: inject(TYPES.walkerCommandService),
7899
+ };
7830
7900
  const logicPrivateServices = {
7831
7901
  backtestLogicPrivateService: inject(TYPES.backtestLogicPrivateService),
7832
7902
  liveLogicPrivateService: inject(TYPES.liveLogicPrivateService),
@@ -7859,6 +7929,7 @@ const backtest = {
7859
7929
  ...connectionServices,
7860
7930
  ...schemaServices,
7861
7931
  ...globalServices,
7932
+ ...commandServices,
7862
7933
  ...logicPrivateServices,
7863
7934
  ...logicPublicServices,
7864
7935
  ...markdownServices,
@@ -9153,7 +9224,7 @@ const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
9153
9224
  /**
9154
9225
  * Utility class for backtest operations.
9155
9226
  *
9156
- * Provides simplified access to backtestGlobalService.run() with logging.
9227
+ * Provides simplified access to backtestCommandService.run() with logging.
9157
9228
  * Exported as singleton instance for convenient usage.
9158
9229
  *
9159
9230
  * @example
@@ -9194,7 +9265,7 @@ class BacktestUtils {
9194
9265
  const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
9195
9266
  riskName && backtest$1.riskGlobalService.clear(riskName);
9196
9267
  }
9197
- return backtest$1.backtestGlobalService.run(symbol, context);
9268
+ return backtest$1.backtestCommandService.run(symbol, context);
9198
9269
  };
9199
9270
  /**
9200
9271
  * Runs backtest in background without yielding results.
@@ -9329,7 +9400,7 @@ const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
9329
9400
  /**
9330
9401
  * Utility class for live trading operations.
9331
9402
  *
9332
- * Provides simplified access to liveGlobalService.run() with logging.
9403
+ * Provides simplified access to liveCommandService.run() with logging.
9333
9404
  * Exported as singleton instance for convenient usage.
9334
9405
  *
9335
9406
  * Features:
@@ -9383,7 +9454,7 @@ class LiveUtils {
9383
9454
  const { riskName } = backtest$1.strategySchemaService.get(context.strategyName);
9384
9455
  riskName && backtest$1.riskGlobalService.clear(riskName);
9385
9456
  }
9386
- return backtest$1.liveGlobalService.run(symbol, context);
9457
+ return backtest$1.liveCommandService.run(symbol, context);
9387
9458
  };
9388
9459
  /**
9389
9460
  * Runs live trading in background without yielding results.
@@ -9769,7 +9840,7 @@ const WALKER_METHOD_NAME_DUMP = "WalkerUtils.dump";
9769
9840
  /**
9770
9841
  * Utility class for walker operations.
9771
9842
  *
9772
- * Provides simplified access to walkerGlobalService.run() with logging.
9843
+ * Provides simplified access to walkerCommandService.run() with logging.
9773
9844
  * Automatically pulls exchangeName and frameName from walker schema.
9774
9845
  * Exported as singleton instance for convenient usage.
9775
9846
  *
@@ -9821,7 +9892,7 @@ class WalkerUtils {
9821
9892
  riskName && backtest$1.riskGlobalService.clear(riskName);
9822
9893
  }
9823
9894
  }
9824
- return backtest$1.walkerGlobalService.run(symbol, {
9895
+ return backtest$1.walkerCommandService.run(symbol, {
9825
9896
  walkerName: context.walkerName,
9826
9897
  exchangeName: walkerSchema.exchangeName,
9827
9898
  frameName: walkerSchema.frameName,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.2.2",
3
+ "version": "1.3.0",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -3595,7 +3595,7 @@ declare const PersistRiskAdapter: PersistRiskUtils;
3595
3595
  /**
3596
3596
  * Utility class for backtest operations.
3597
3597
  *
3598
- * Provides simplified access to backtestGlobalService.run() with logging.
3598
+ * Provides simplified access to backtestCommandService.run() with logging.
3599
3599
  * Exported as singleton instance for convenient usage.
3600
3600
  *
3601
3601
  * @example
@@ -3716,7 +3716,7 @@ declare const Backtest: BacktestUtils;
3716
3716
  /**
3717
3717
  * Utility class for live trading operations.
3718
3718
  *
3719
- * Provides simplified access to liveGlobalService.run() with logging.
3719
+ * Provides simplified access to liveCommandService.run() with logging.
3720
3720
  * Exported as singleton instance for convenient usage.
3721
3721
  *
3722
3722
  * Features:
@@ -4063,7 +4063,7 @@ declare class Performance {
4063
4063
  /**
4064
4064
  * Utility class for walker operations.
4065
4065
  *
4066
- * Provides simplified access to walkerGlobalService.run() with logging.
4066
+ * Provides simplified access to walkerCommandService.run() with logging.
4067
4067
  * Automatically pulls exchangeName and frameName from walker schema.
4068
4068
  * Exported as singleton instance for convenient usage.
4069
4069
  *
@@ -5315,7 +5315,7 @@ declare class RiskGlobalService {
5315
5315
  * Simple wrapper around WalkerLogicPublicService for dependency injection.
5316
5316
  * Used by public API exports.
5317
5317
  */
5318
- declare class WalkerGlobalService {
5318
+ declare class WalkerCommandService {
5319
5319
  private readonly loggerService;
5320
5320
  private readonly walkerLogicPublicService;
5321
5321
  private readonly walkerSchemaService;
@@ -5898,7 +5898,7 @@ declare class WalkerLogicPublicService {
5898
5898
  * Simple wrapper around LiveLogicPublicService for dependency injection.
5899
5899
  * Used by public API exports.
5900
5900
  */
5901
- declare class LiveGlobalService {
5901
+ declare class LiveCommandService {
5902
5902
  private readonly loggerService;
5903
5903
  private readonly liveLogicPublicService;
5904
5904
  private readonly strategyValidationService;
@@ -5926,7 +5926,7 @@ declare class LiveGlobalService {
5926
5926
  * Simple wrapper around BacktestLogicPublicService for dependency injection.
5927
5927
  * Used by public API exports.
5928
5928
  */
5929
- declare class BacktestGlobalService {
5929
+ declare class BacktestCommandService {
5930
5930
  private readonly loggerService;
5931
5931
  private readonly strategySchemaService;
5932
5932
  private readonly riskValidationService;
@@ -6338,12 +6338,12 @@ declare const backtest: {
6338
6338
  backtestLogicPrivateService: BacktestLogicPrivateService;
6339
6339
  liveLogicPrivateService: LiveLogicPrivateService;
6340
6340
  walkerLogicPrivateService: WalkerLogicPrivateService;
6341
+ liveCommandService: LiveCommandService;
6342
+ backtestCommandService: BacktestCommandService;
6343
+ walkerCommandService: WalkerCommandService;
6341
6344
  exchangeGlobalService: ExchangeGlobalService;
6342
6345
  strategyGlobalService: StrategyGlobalService;
6343
6346
  frameGlobalService: FrameGlobalService;
6344
- liveGlobalService: LiveGlobalService;
6345
- backtestGlobalService: BacktestGlobalService;
6346
- walkerGlobalService: WalkerGlobalService;
6347
6347
  sizingGlobalService: SizingGlobalService;
6348
6348
  riskGlobalService: RiskGlobalService;
6349
6349
  exchangeSchemaService: ExchangeSchemaService;