backtest-kit 1.13.3 → 2.0.1
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/README.md +8 -8
- package/build/index.cjs +1063 -368
- package/build/index.mjs +1014 -332
- package/package.json +1 -1
- package/types.d.ts +3266 -2843
package/build/index.cjs
CHANGED
|
@@ -541,14 +541,21 @@ const breakevenSubject = new functoolsKit.Subject();
|
|
|
541
541
|
*/
|
|
542
542
|
const riskSubject = new functoolsKit.Subject();
|
|
543
543
|
/**
|
|
544
|
-
*
|
|
544
|
+
* Schedule ping emitter for scheduled signal monitoring events.
|
|
545
545
|
* Emits every minute when a scheduled signal is being monitored (waiting for activation).
|
|
546
546
|
* Allows users to track scheduled signal lifecycle and implement custom cancellation logic.
|
|
547
547
|
*/
|
|
548
|
-
const
|
|
548
|
+
const schedulePingSubject = new functoolsKit.Subject();
|
|
549
|
+
/**
|
|
550
|
+
* Active ping emitter for active pending signal monitoring events.
|
|
551
|
+
* Emits every minute when an active pending signal is being monitored.
|
|
552
|
+
* Allows users to track active signal lifecycle and implement custom dynamic management logic.
|
|
553
|
+
*/
|
|
554
|
+
const activePingSubject = new functoolsKit.Subject();
|
|
549
555
|
|
|
550
556
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
551
557
|
__proto__: null,
|
|
558
|
+
activePingSubject: activePingSubject,
|
|
552
559
|
breakevenSubject: breakevenSubject,
|
|
553
560
|
doneBacktestSubject: doneBacktestSubject,
|
|
554
561
|
doneLiveSubject: doneLiveSubject,
|
|
@@ -558,11 +565,11 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
558
565
|
partialLossSubject: partialLossSubject,
|
|
559
566
|
partialProfitSubject: partialProfitSubject,
|
|
560
567
|
performanceEmitter: performanceEmitter,
|
|
561
|
-
pingSubject: pingSubject,
|
|
562
568
|
progressBacktestEmitter: progressBacktestEmitter,
|
|
563
569
|
progressOptimizerEmitter: progressOptimizerEmitter,
|
|
564
570
|
progressWalkerEmitter: progressWalkerEmitter,
|
|
565
571
|
riskSubject: riskSubject,
|
|
572
|
+
schedulePingSubject: schedulePingSubject,
|
|
566
573
|
signalBacktestEmitter: signalBacktestEmitter,
|
|
567
574
|
signalEmitter: signalEmitter,
|
|
568
575
|
signalLiveEmitter: signalLiveEmitter,
|
|
@@ -773,11 +780,16 @@ class ClientExchange {
|
|
|
773
780
|
const whenTimestamp = this.params.execution.context.when.getTime();
|
|
774
781
|
const sinceTimestamp = since.getTime();
|
|
775
782
|
const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
|
|
776
|
-
|
|
777
|
-
|
|
783
|
+
// Apply distinct by timestamp to remove duplicates
|
|
784
|
+
const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
|
|
785
|
+
if (filteredData.length !== uniqueData.length) {
|
|
786
|
+
this.params.logger.warn(`ClientExchange Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
|
|
778
787
|
}
|
|
779
|
-
|
|
780
|
-
|
|
788
|
+
if (uniqueData.length < limit) {
|
|
789
|
+
this.params.logger.warn(`ClientExchange Expected ${limit} candles, got ${uniqueData.length}`);
|
|
790
|
+
}
|
|
791
|
+
await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, uniqueData);
|
|
792
|
+
return uniqueData;
|
|
781
793
|
}
|
|
782
794
|
/**
|
|
783
795
|
* Fetches future candles forwards from execution context time.
|
|
@@ -826,11 +838,16 @@ class ClientExchange {
|
|
|
826
838
|
// Filter candles to strictly match the requested range
|
|
827
839
|
const sinceTimestamp = since.getTime();
|
|
828
840
|
const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= endTime);
|
|
829
|
-
|
|
830
|
-
|
|
841
|
+
// Apply distinct by timestamp to remove duplicates
|
|
842
|
+
const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
|
|
843
|
+
if (filteredData.length !== uniqueData.length) {
|
|
844
|
+
this.params.logger.warn(`ClientExchange getNextCandles: Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
|
|
845
|
+
}
|
|
846
|
+
if (uniqueData.length < limit) {
|
|
847
|
+
this.params.logger.warn(`ClientExchange getNextCandles: Expected ${limit} candles, got ${uniqueData.length}`);
|
|
831
848
|
}
|
|
832
|
-
await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit,
|
|
833
|
-
return
|
|
849
|
+
await CALL_CANDLE_DATA_CALLBACKS_FN(this, symbol, interval, since, limit, uniqueData);
|
|
850
|
+
return uniqueData;
|
|
834
851
|
}
|
|
835
852
|
/**
|
|
836
853
|
* Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
|
|
@@ -3406,14 +3423,40 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
3406
3423
|
await CALL_TICK_CALLBACKS_FN(self, self.params.execution.context.symbol, result, activationTime, self.params.execution.context.backtest);
|
|
3407
3424
|
return result;
|
|
3408
3425
|
};
|
|
3409
|
-
const
|
|
3426
|
+
const CALL_SCHEDULE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, scheduled, timestamp, backtest) => {
|
|
3410
3427
|
await ExecutionContextService.runInContext(async () => {
|
|
3411
3428
|
const publicSignal = TO_PUBLIC_SIGNAL(scheduled);
|
|
3412
|
-
// Call system
|
|
3413
|
-
await self.params.
|
|
3414
|
-
// Call user
|
|
3415
|
-
if (self.params.callbacks?.
|
|
3416
|
-
await self.params.callbacks.
|
|
3429
|
+
// Call system onSchedulePing callback first (emits to pingSubject)
|
|
3430
|
+
await self.params.onSchedulePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, self.params.execution.context.backtest, timestamp);
|
|
3431
|
+
// Call user onSchedulePing callback only if signal is still active (not cancelled, not activated)
|
|
3432
|
+
if (self.params.callbacks?.onSchedulePing) {
|
|
3433
|
+
await self.params.callbacks.onSchedulePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
3434
|
+
}
|
|
3435
|
+
}, {
|
|
3436
|
+
when: new Date(timestamp),
|
|
3437
|
+
symbol: symbol,
|
|
3438
|
+
backtest: backtest,
|
|
3439
|
+
});
|
|
3440
|
+
}), {
|
|
3441
|
+
fallback: (error) => {
|
|
3442
|
+
const message = "ClientStrategy CALL_SCHEDULE_PING_CALLBACKS_FN thrown";
|
|
3443
|
+
const payload = {
|
|
3444
|
+
error: functoolsKit.errorData(error),
|
|
3445
|
+
message: functoolsKit.getErrorMessage(error),
|
|
3446
|
+
};
|
|
3447
|
+
backtest$1.loggerService.warn(message, payload);
|
|
3448
|
+
console.warn(message, payload);
|
|
3449
|
+
errorEmitter.next(error);
|
|
3450
|
+
},
|
|
3451
|
+
});
|
|
3452
|
+
const CALL_ACTIVE_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symbol, pending, timestamp, backtest) => {
|
|
3453
|
+
await ExecutionContextService.runInContext(async () => {
|
|
3454
|
+
const publicSignal = TO_PUBLIC_SIGNAL(pending);
|
|
3455
|
+
// Call system onActivePing callback first (emits to activePingSubject)
|
|
3456
|
+
await self.params.onActivePing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, publicSignal, self.params.execution.context.backtest, timestamp);
|
|
3457
|
+
// Call user onActivePing callback only if signal is still active (not closed)
|
|
3458
|
+
if (self.params.callbacks?.onActivePing) {
|
|
3459
|
+
await self.params.callbacks.onActivePing(self.params.execution.context.symbol, publicSignal, new Date(timestamp), self.params.execution.context.backtest);
|
|
3417
3460
|
}
|
|
3418
3461
|
}, {
|
|
3419
3462
|
when: new Date(timestamp),
|
|
@@ -3422,7 +3465,7 @@ const CALL_PING_CALLBACKS_FN = functoolsKit.trycatch(beginTime(async (self, symb
|
|
|
3422
3465
|
});
|
|
3423
3466
|
}), {
|
|
3424
3467
|
fallback: (error) => {
|
|
3425
|
-
const message = "ClientStrategy
|
|
3468
|
+
const message = "ClientStrategy CALL_ACTIVE_PING_CALLBACKS_FN thrown";
|
|
3426
3469
|
const payload = {
|
|
3427
3470
|
error: functoolsKit.errorData(error),
|
|
3428
3471
|
message: functoolsKit.getErrorMessage(error),
|
|
@@ -3794,10 +3837,10 @@ const CALL_BREAKEVEN_CLEAR_FN = functoolsKit.trycatch(beginTime(async (self, sym
|
|
|
3794
3837
|
});
|
|
3795
3838
|
const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
|
|
3796
3839
|
const currentTime = self.params.execution.context.when.getTime();
|
|
3797
|
-
await
|
|
3840
|
+
await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, currentTime, self.params.execution.context.backtest);
|
|
3798
3841
|
const pnl = toProfitLossDto(scheduled, currentPrice);
|
|
3799
3842
|
const result = {
|
|
3800
|
-
action: "
|
|
3843
|
+
action: "waiting",
|
|
3801
3844
|
signal: TO_PUBLIC_SIGNAL(scheduled),
|
|
3802
3845
|
currentPrice: currentPrice,
|
|
3803
3846
|
strategyName: self.params.method.context.strategyName,
|
|
@@ -3924,6 +3967,7 @@ const RETURN_PENDING_SIGNAL_ACTIVE_FN = async (self, signal, currentPrice) => {
|
|
|
3924
3967
|
let percentTp = 0;
|
|
3925
3968
|
let percentSl = 0;
|
|
3926
3969
|
const currentTime = self.params.execution.context.when.getTime();
|
|
3970
|
+
await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentTime, self.params.execution.context.backtest);
|
|
3927
3971
|
// Calculate percentage of path to TP/SL for partial fill/loss callbacks
|
|
3928
3972
|
{
|
|
3929
3973
|
if (signal.position === "long") {
|
|
@@ -4129,7 +4173,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
4129
4173
|
const averagePrice = GET_AVG_PRICE_FN(recentCandles);
|
|
4130
4174
|
// КРИТИЧНО: Проверяем был ли сигнал отменен пользователем через cancel()
|
|
4131
4175
|
if (self._cancelledSignal) {
|
|
4132
|
-
// Сигнал был отменен через cancel() в
|
|
4176
|
+
// Сигнал был отменен через cancel() в onSchedulePing
|
|
4133
4177
|
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user");
|
|
4134
4178
|
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
4135
4179
|
}
|
|
@@ -4186,7 +4230,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
4186
4230
|
result: null,
|
|
4187
4231
|
};
|
|
4188
4232
|
}
|
|
4189
|
-
await
|
|
4233
|
+
await CALL_SCHEDULE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, scheduled, candle.timestamp, true);
|
|
4190
4234
|
}
|
|
4191
4235
|
return {
|
|
4192
4236
|
activated: false,
|
|
@@ -4212,6 +4256,7 @@ const PROCESS_PENDING_SIGNAL_CANDLES_FN = async (self, signal, candles) => {
|
|
|
4212
4256
|
const startIndex = Math.max(0, i - (candlesCount - 1));
|
|
4213
4257
|
const recentCandles = candles.slice(startIndex, i + 1);
|
|
4214
4258
|
const averagePrice = GET_AVG_PRICE_FN(recentCandles);
|
|
4259
|
+
await CALL_ACTIVE_PING_CALLBACKS_FN(self, self.params.execution.context.symbol, signal, currentCandleTimestamp, true);
|
|
4215
4260
|
let shouldClose = false;
|
|
4216
4261
|
let closeReason;
|
|
4217
4262
|
// Check time expiration FIRST (КРИТИЧНО!)
|
|
@@ -4757,7 +4802,15 @@ class ClientStrategy {
|
|
|
4757
4802
|
return result;
|
|
4758
4803
|
}
|
|
4759
4804
|
if (activated) {
|
|
4760
|
-
|
|
4805
|
+
// КРИТИЧНО: activationIndex - индекс свечи активации в массиве candles
|
|
4806
|
+
// BacktestLogicPrivateService включил буфер в начало массива, поэтому перед activationIndex достаточно свечей
|
|
4807
|
+
// PROCESS_PENDING_SIGNAL_CANDLES_FN пропустит первые bufferCandlesCount свечей для VWAP
|
|
4808
|
+
// Чтобы обработка началась со СЛЕДУЮЩЕЙ свечи после активации (activationIndex + 1),
|
|
4809
|
+
// нужно взять срез начиная с (activationIndex + 1 - bufferCandlesCount)
|
|
4810
|
+
// Это даст буфер ИЗ scheduled фазы + свеча после активации как первая обрабатываемая
|
|
4811
|
+
const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
|
|
4812
|
+
const sliceStart = Math.max(0, activationIndex + 1 - bufferCandlesCount);
|
|
4813
|
+
const remainingCandles = candles.slice(sliceStart);
|
|
4761
4814
|
if (remainingCandles.length === 0) {
|
|
4762
4815
|
const candlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT;
|
|
4763
4816
|
const recentCandles = candles.slice(Math.max(0, activationIndex - (candlesCount - 1)), activationIndex + 1);
|
|
@@ -4773,35 +4826,23 @@ class ClientStrategy {
|
|
|
4773
4826
|
const lastCandleTimestamp = candles[candles.length - 1].timestamp;
|
|
4774
4827
|
const elapsedTime = lastCandleTimestamp - scheduled.scheduledAt;
|
|
4775
4828
|
if (elapsedTime < maxTimeToWait) {
|
|
4776
|
-
//
|
|
4777
|
-
//
|
|
4778
|
-
|
|
4779
|
-
const
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
signal: TO_PUBLIC_SIGNAL(scheduled),
|
|
4794
|
-
currentPrice: lastPrice,
|
|
4795
|
-
percentSl: 0,
|
|
4796
|
-
percentTp: 0,
|
|
4797
|
-
pnl,
|
|
4798
|
-
strategyName: this.params.method.context.strategyName,
|
|
4799
|
-
exchangeName: this.params.method.context.exchangeName,
|
|
4800
|
-
frameName: this.params.method.context.frameName,
|
|
4801
|
-
symbol: this.params.execution.context.symbol,
|
|
4802
|
-
backtest: this.params.execution.context.backtest,
|
|
4803
|
-
};
|
|
4804
|
-
return result; // Cast to IStrategyBacktestResult (which includes Active)
|
|
4829
|
+
// EDGE CASE: backtest() called with partial candle data (should never happen in production)
|
|
4830
|
+
// In real backtest flow this won't happen as we process all candles at once
|
|
4831
|
+
// This indicates incorrect usage of backtest() - throw error instead of returning partial result
|
|
4832
|
+
const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
|
|
4833
|
+
// For scheduled signal that has NOT activated: buffer + wait time only (no lifetime yet)
|
|
4834
|
+
const requiredCandlesCount = bufferCandlesCount + GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES + 1;
|
|
4835
|
+
throw new Error(functoolsKit.str.newline(`ClientStrategy backtest: Insufficient candle data for scheduled signal (not yet activated). ` +
|
|
4836
|
+
`Signal scheduled at ${new Date(scheduled.scheduledAt).toISOString()}, ` +
|
|
4837
|
+
`last candle at ${new Date(lastCandleTimestamp).toISOString()}. ` +
|
|
4838
|
+
`Elapsed: ${Math.floor(elapsedTime / 60000)}min of ${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES}min wait time. ` +
|
|
4839
|
+
`Provided ${candles.length} candles, but need at least ${requiredCandlesCount} candles. ` +
|
|
4840
|
+
`\nBreakdown: ` +
|
|
4841
|
+
`${bufferCandlesCount} buffer (VWAP) + ` +
|
|
4842
|
+
`${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES} wait (for activation) = ${requiredCandlesCount} total. ` +
|
|
4843
|
+
`\nBuffer explanation: VWAP calculation requires ${GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT} candles, ` +
|
|
4844
|
+
`so first ${bufferCandlesCount} candles are skipped during scheduled phase processing. ` +
|
|
4845
|
+
`Provide complete candle range: [scheduledAt - ${bufferCandlesCount}min, scheduledAt + ${GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES}min].`));
|
|
4805
4846
|
}
|
|
4806
4847
|
// Timeout reached - cancel the scheduled signal
|
|
4807
4848
|
const candlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT;
|
|
@@ -4831,9 +4872,29 @@ class ClientStrategy {
|
|
|
4831
4872
|
if (closedResult) {
|
|
4832
4873
|
return closedResult;
|
|
4833
4874
|
}
|
|
4875
|
+
// Signal didn't close during candle processing - check if we have enough data
|
|
4834
4876
|
const lastCandles = candles.slice(-GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT);
|
|
4835
4877
|
const lastPrice = GET_AVG_PRICE_FN(lastCandles);
|
|
4836
4878
|
const closeTimestamp = lastCandles[lastCandles.length - 1].timestamp;
|
|
4879
|
+
const signalTime = signal.pendingAt;
|
|
4880
|
+
const maxTimeToWait = signal.minuteEstimatedTime * 60 * 1000;
|
|
4881
|
+
const elapsedTime = closeTimestamp - signalTime;
|
|
4882
|
+
// Check if we actually reached time expiration or just ran out of candles
|
|
4883
|
+
if (elapsedTime < maxTimeToWait) {
|
|
4884
|
+
// EDGE CASE: backtest() called with insufficient candle data
|
|
4885
|
+
const bufferCandlesCount = GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT - 1;
|
|
4886
|
+
const requiredCandlesCount = signal.minuteEstimatedTime + bufferCandlesCount + 1;
|
|
4887
|
+
throw new Error(functoolsKit.str.newline(`ClientStrategy backtest: Insufficient candle data for pending signal. ` +
|
|
4888
|
+
`Signal opened at ${new Date(signal.pendingAt).toISOString()}, ` +
|
|
4889
|
+
`last candle at ${new Date(closeTimestamp).toISOString()}. ` +
|
|
4890
|
+
`Elapsed: ${Math.floor(elapsedTime / 60000)}min of ${signal.minuteEstimatedTime}min required. ` +
|
|
4891
|
+
`Provided ${candles.length} candles, but need at least ${requiredCandlesCount} candles. ` +
|
|
4892
|
+
`\nBreakdown: ${signal.minuteEstimatedTime} candles for signal lifetime + ${bufferCandlesCount} buffer candles. ` +
|
|
4893
|
+
`\nBuffer explanation: VWAP calculation requires ${GLOBAL_CONFIG.CC_AVG_PRICE_CANDLES_COUNT} candles, ` +
|
|
4894
|
+
`so first ${bufferCandlesCount} candles are skipped to ensure accurate price averaging. ` +
|
|
4895
|
+
`Provide complete candle range: [pendingAt - ${bufferCandlesCount}min, pendingAt + ${signal.minuteEstimatedTime}min].`));
|
|
4896
|
+
}
|
|
4897
|
+
// Time actually expired - close with time_expired
|
|
4837
4898
|
return await CLOSE_PENDING_SIGNAL_IN_BACKTEST_FN(this, signal, lastPrice, "time_expired", closeTimestamp);
|
|
4838
4899
|
}
|
|
4839
4900
|
/**
|
|
@@ -5622,6 +5683,9 @@ class ClientStrategy {
|
|
|
5622
5683
|
const RISK_METHOD_NAME_GET_DATA = "RiskUtils.getData";
|
|
5623
5684
|
const RISK_METHOD_NAME_GET_REPORT = "RiskUtils.getReport";
|
|
5624
5685
|
const RISK_METHOD_NAME_DUMP = "RiskUtils.dump";
|
|
5686
|
+
const RISK_METHOD_NAME_CHECK_SIGNAL = "MergeRisk.checkSignal";
|
|
5687
|
+
const RISK_METHOD_NAME_ADD_SIGNAL = "MergeRisk.addSignal";
|
|
5688
|
+
const RISK_METHOD_NAME_REMOVE_SIGNAL = "MergeRisk.removeSignal";
|
|
5625
5689
|
/**
|
|
5626
5690
|
* Composite risk management class that combines multiple risk profiles.
|
|
5627
5691
|
*
|
|
@@ -5677,7 +5741,7 @@ class MergeRisk {
|
|
|
5677
5741
|
* @returns Promise resolving to true if all risks approve, false if any risk rejects
|
|
5678
5742
|
*/
|
|
5679
5743
|
async checkSignal(params) {
|
|
5680
|
-
backtest$1.loggerService.info(
|
|
5744
|
+
backtest$1.loggerService.info(RISK_METHOD_NAME_CHECK_SIGNAL, {
|
|
5681
5745
|
params,
|
|
5682
5746
|
});
|
|
5683
5747
|
for (const [riskName, risk] of Object.entries(this._riskMap)) {
|
|
@@ -5701,7 +5765,7 @@ class MergeRisk {
|
|
|
5701
5765
|
* @returns Promise that resolves when all risks have registered the signal
|
|
5702
5766
|
*/
|
|
5703
5767
|
async addSignal(symbol, context, positionData) {
|
|
5704
|
-
backtest$1.loggerService.info(
|
|
5768
|
+
backtest$1.loggerService.info(RISK_METHOD_NAME_ADD_SIGNAL, {
|
|
5705
5769
|
symbol,
|
|
5706
5770
|
context,
|
|
5707
5771
|
});
|
|
@@ -5718,7 +5782,7 @@ class MergeRisk {
|
|
|
5718
5782
|
* @returns Promise that resolves when all risks have removed the signal
|
|
5719
5783
|
*/
|
|
5720
5784
|
async removeSignal(symbol, context) {
|
|
5721
|
-
backtest$1.loggerService.info(
|
|
5785
|
+
backtest$1.loggerService.info(RISK_METHOD_NAME_REMOVE_SIGNAL, {
|
|
5722
5786
|
symbol,
|
|
5723
5787
|
context,
|
|
5724
5788
|
});
|
|
@@ -6001,15 +6065,36 @@ const CREATE_KEY_FN$k = (symbol, strategyName, exchangeName, frameName, backtest
|
|
|
6001
6065
|
return parts.join(":");
|
|
6002
6066
|
};
|
|
6003
6067
|
/**
|
|
6004
|
-
* Creates a callback function for emitting ping events to pingSubject.
|
|
6068
|
+
* Creates a callback function for emitting schedule ping events to pingSubject.
|
|
6005
6069
|
*
|
|
6006
6070
|
* Called by ClientStrategy when a scheduled signal is being monitored every minute.
|
|
6007
6071
|
* Emits PingContract event to all subscribers and calls ActionCoreService.
|
|
6008
6072
|
*
|
|
6009
6073
|
* @param self - Reference to StrategyConnectionService instance
|
|
6010
|
-
* @returns Callback function for ping events
|
|
6074
|
+
* @returns Callback function for schedule ping events
|
|
6075
|
+
*/
|
|
6076
|
+
const CREATE_COMMIT_SCHEDULE_PING_FN = (self) => async (symbol, strategyName, exchangeName, data, backtest, timestamp) => {
|
|
6077
|
+
const event = {
|
|
6078
|
+
symbol,
|
|
6079
|
+
strategyName,
|
|
6080
|
+
exchangeName,
|
|
6081
|
+
data,
|
|
6082
|
+
backtest,
|
|
6083
|
+
timestamp,
|
|
6084
|
+
};
|
|
6085
|
+
await schedulePingSubject.next(event);
|
|
6086
|
+
await self.actionCoreService.pingScheduled(backtest, event, { strategyName, exchangeName, frameName: data.frameName });
|
|
6087
|
+
};
|
|
6088
|
+
/**
|
|
6089
|
+
* Creates a callback function for emitting active ping events.
|
|
6090
|
+
*
|
|
6091
|
+
* Called by ClientStrategy when an active pending signal is being monitored every minute.
|
|
6092
|
+
* Placeholder for future activePingSubject implementation.
|
|
6093
|
+
*
|
|
6094
|
+
* @param self - Reference to StrategyConnectionService instance
|
|
6095
|
+
* @returns Callback function for active ping events
|
|
6011
6096
|
*/
|
|
6012
|
-
const
|
|
6097
|
+
const CREATE_COMMIT_ACTIVE_PING_FN = (self) => async (symbol, strategyName, exchangeName, data, backtest, timestamp) => {
|
|
6013
6098
|
const event = {
|
|
6014
6099
|
symbol,
|
|
6015
6100
|
strategyName,
|
|
@@ -6018,8 +6103,8 @@ const CREATE_COMMIT_PING_FN = (self) => async (symbol, strategyName, exchangeNam
|
|
|
6018
6103
|
backtest,
|
|
6019
6104
|
timestamp,
|
|
6020
6105
|
};
|
|
6021
|
-
await
|
|
6022
|
-
await self.actionCoreService.
|
|
6106
|
+
await activePingSubject.next(event);
|
|
6107
|
+
await self.actionCoreService.pingActive(backtest, event, { strategyName, exchangeName, frameName: data.frameName });
|
|
6023
6108
|
};
|
|
6024
6109
|
/**
|
|
6025
6110
|
* Creates a callback function for emitting init events.
|
|
@@ -6116,7 +6201,8 @@ class StrategyConnectionService {
|
|
|
6116
6201
|
getSignal,
|
|
6117
6202
|
callbacks,
|
|
6118
6203
|
onInit: CREATE_COMMIT_INIT_FN(this),
|
|
6119
|
-
|
|
6204
|
+
onSchedulePing: CREATE_COMMIT_SCHEDULE_PING_FN(this),
|
|
6205
|
+
onActivePing: CREATE_COMMIT_ACTIVE_PING_FN(this),
|
|
6120
6206
|
onDispose: CREATE_COMMIT_DISPOSE_FN(this),
|
|
6121
6207
|
});
|
|
6122
6208
|
});
|
|
@@ -7509,8 +7595,8 @@ const CALL_SIGNAL_BACKTEST_CALLBACK_FN = functoolsKit.trycatch(async (self, even
|
|
|
7509
7595
|
});
|
|
7510
7596
|
/** Wrapper to call breakeven callback with error handling */
|
|
7511
7597
|
const CALL_BREAKEVEN_CALLBACK_FN = functoolsKit.trycatch(async (self, event, strategyName, frameName, backtest) => {
|
|
7512
|
-
if (self.params.callbacks?.
|
|
7513
|
-
await self.params.callbacks.
|
|
7598
|
+
if (self.params.callbacks?.onBreakevenAvailable) {
|
|
7599
|
+
await self.params.callbacks.onBreakevenAvailable(event, self.params.actionName, strategyName, frameName, backtest);
|
|
7514
7600
|
}
|
|
7515
7601
|
}, {
|
|
7516
7602
|
fallback: (error) => {
|
|
@@ -7526,8 +7612,8 @@ const CALL_BREAKEVEN_CALLBACK_FN = functoolsKit.trycatch(async (self, event, str
|
|
|
7526
7612
|
});
|
|
7527
7613
|
/** Wrapper to call partialProfit callback with error handling */
|
|
7528
7614
|
const CALL_PARTIAL_PROFIT_CALLBACK_FN = functoolsKit.trycatch(async (self, event, strategyName, frameName, backtest) => {
|
|
7529
|
-
if (self.params.callbacks?.
|
|
7530
|
-
await self.params.callbacks.
|
|
7615
|
+
if (self.params.callbacks?.onPartialProfitAvailable) {
|
|
7616
|
+
await self.params.callbacks.onPartialProfitAvailable(event, self.params.actionName, strategyName, frameName, backtest);
|
|
7531
7617
|
}
|
|
7532
7618
|
}, {
|
|
7533
7619
|
fallback: (error) => {
|
|
@@ -7543,8 +7629,8 @@ const CALL_PARTIAL_PROFIT_CALLBACK_FN = functoolsKit.trycatch(async (self, event
|
|
|
7543
7629
|
});
|
|
7544
7630
|
/** Wrapper to call partialLoss callback with error handling */
|
|
7545
7631
|
const CALL_PARTIAL_LOSS_CALLBACK_FN = functoolsKit.trycatch(async (self, event, strategyName, frameName, backtest) => {
|
|
7546
|
-
if (self.params.callbacks?.
|
|
7547
|
-
await self.params.callbacks.
|
|
7632
|
+
if (self.params.callbacks?.onPartialLossAvailable) {
|
|
7633
|
+
await self.params.callbacks.onPartialLossAvailable(event, self.params.actionName, strategyName, frameName, backtest);
|
|
7548
7634
|
}
|
|
7549
7635
|
}, {
|
|
7550
7636
|
fallback: (error) => {
|
|
@@ -7558,14 +7644,31 @@ const CALL_PARTIAL_LOSS_CALLBACK_FN = functoolsKit.trycatch(async (self, event,
|
|
|
7558
7644
|
errorEmitter.next(error);
|
|
7559
7645
|
},
|
|
7560
7646
|
});
|
|
7561
|
-
/** Wrapper to call ping callback with error handling */
|
|
7562
|
-
const
|
|
7563
|
-
if (self.params.callbacks?.
|
|
7564
|
-
await self.params.callbacks.
|
|
7647
|
+
/** Wrapper to call scheduled ping callback with error handling */
|
|
7648
|
+
const CALL_PING_SCHEDULED_CALLBACK_FN = functoolsKit.trycatch(async (self, event, strategyName, frameName, backtest) => {
|
|
7649
|
+
if (self.params.callbacks?.onPingScheduled) {
|
|
7650
|
+
await self.params.callbacks.onPingScheduled(event, self.params.actionName, strategyName, frameName, backtest);
|
|
7651
|
+
}
|
|
7652
|
+
}, {
|
|
7653
|
+
fallback: (error) => {
|
|
7654
|
+
const message = "ClientAction CALL_PING_SCHEDULED_CALLBACK_FN thrown";
|
|
7655
|
+
const payload = {
|
|
7656
|
+
error: functoolsKit.errorData(error),
|
|
7657
|
+
message: functoolsKit.getErrorMessage(error),
|
|
7658
|
+
};
|
|
7659
|
+
backtest$1.loggerService.warn(message, payload);
|
|
7660
|
+
console.warn(message, payload);
|
|
7661
|
+
errorEmitter.next(error);
|
|
7662
|
+
},
|
|
7663
|
+
});
|
|
7664
|
+
/** Wrapper to call active ping callback with error handling */
|
|
7665
|
+
const CALL_PING_ACTIVE_CALLBACK_FN = functoolsKit.trycatch(async (self, event, strategyName, frameName, backtest) => {
|
|
7666
|
+
if (self.params.callbacks?.onPingActive) {
|
|
7667
|
+
await self.params.callbacks.onPingActive(event, self.params.actionName, strategyName, frameName, backtest);
|
|
7565
7668
|
}
|
|
7566
7669
|
}, {
|
|
7567
7670
|
fallback: (error) => {
|
|
7568
|
-
const message = "ClientAction
|
|
7671
|
+
const message = "ClientAction CALL_PING_ACTIVE_CALLBACK_FN thrown";
|
|
7569
7672
|
const payload = {
|
|
7570
7673
|
error: functoolsKit.errorData(error),
|
|
7571
7674
|
message: functoolsKit.getErrorMessage(error),
|
|
@@ -7640,6 +7743,7 @@ const CREATE_HANDLER_FN = (self) => {
|
|
|
7640
7743
|
self.params.strategyName,
|
|
7641
7744
|
self.params.frameName,
|
|
7642
7745
|
self.params.actionName,
|
|
7746
|
+
self.params.backtest,
|
|
7643
7747
|
]);
|
|
7644
7748
|
}
|
|
7645
7749
|
return self.params.handler;
|
|
@@ -7831,8 +7935,8 @@ class ClientAction {
|
|
|
7831
7935
|
/**
|
|
7832
7936
|
* Handles breakeven events when stop-loss is moved to entry price.
|
|
7833
7937
|
*/
|
|
7834
|
-
async
|
|
7835
|
-
this.params.logger.debug("ClientAction
|
|
7938
|
+
async breakevenAvailable(event) {
|
|
7939
|
+
this.params.logger.debug("ClientAction breakevenAvailable", {
|
|
7836
7940
|
actionName: this.params.actionName,
|
|
7837
7941
|
strategyName: this.params.strategyName,
|
|
7838
7942
|
frameName: this.params.frameName,
|
|
@@ -7841,8 +7945,8 @@ class ClientAction {
|
|
|
7841
7945
|
await this.waitForInit();
|
|
7842
7946
|
}
|
|
7843
7947
|
// Call handler method if defined
|
|
7844
|
-
if (this._handlerInstance?.
|
|
7845
|
-
await this._handlerInstance.
|
|
7948
|
+
if (this._handlerInstance?.breakevenAvailable) {
|
|
7949
|
+
await this._handlerInstance.breakevenAvailable(event);
|
|
7846
7950
|
}
|
|
7847
7951
|
// Call callback if defined
|
|
7848
7952
|
await CALL_BREAKEVEN_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
@@ -7851,8 +7955,8 @@ class ClientAction {
|
|
|
7851
7955
|
/**
|
|
7852
7956
|
* Handles partial profit level events (10%, 20%, 30%, etc).
|
|
7853
7957
|
*/
|
|
7854
|
-
async
|
|
7855
|
-
this.params.logger.debug("ClientAction
|
|
7958
|
+
async partialProfitAvailable(event) {
|
|
7959
|
+
this.params.logger.debug("ClientAction partialProfitAvailable", {
|
|
7856
7960
|
actionName: this.params.actionName,
|
|
7857
7961
|
strategyName: this.params.strategyName,
|
|
7858
7962
|
frameName: this.params.frameName,
|
|
@@ -7861,8 +7965,8 @@ class ClientAction {
|
|
|
7861
7965
|
await this.waitForInit();
|
|
7862
7966
|
}
|
|
7863
7967
|
// Call handler method if defined
|
|
7864
|
-
if (this._handlerInstance?.
|
|
7865
|
-
await this._handlerInstance.
|
|
7968
|
+
if (this._handlerInstance?.partialProfitAvailable) {
|
|
7969
|
+
await this._handlerInstance.partialProfitAvailable(event);
|
|
7866
7970
|
}
|
|
7867
7971
|
// Call callback if defined
|
|
7868
7972
|
await CALL_PARTIAL_PROFIT_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
@@ -7871,8 +7975,8 @@ class ClientAction {
|
|
|
7871
7975
|
/**
|
|
7872
7976
|
* Handles partial loss level events (-10%, -20%, -30%, etc).
|
|
7873
7977
|
*/
|
|
7874
|
-
async
|
|
7875
|
-
this.params.logger.debug("ClientAction
|
|
7978
|
+
async partialLossAvailable(event) {
|
|
7979
|
+
this.params.logger.debug("ClientAction partialLossAvailable", {
|
|
7876
7980
|
actionName: this.params.actionName,
|
|
7877
7981
|
strategyName: this.params.strategyName,
|
|
7878
7982
|
frameName: this.params.frameName,
|
|
@@ -7881,18 +7985,38 @@ class ClientAction {
|
|
|
7881
7985
|
await this.waitForInit();
|
|
7882
7986
|
}
|
|
7883
7987
|
// Call handler method if defined
|
|
7884
|
-
if (this._handlerInstance?.
|
|
7885
|
-
await this._handlerInstance.
|
|
7988
|
+
if (this._handlerInstance?.partialLossAvailable) {
|
|
7989
|
+
await this._handlerInstance.partialLossAvailable(event);
|
|
7886
7990
|
}
|
|
7887
7991
|
// Call callback if defined
|
|
7888
7992
|
await CALL_PARTIAL_LOSS_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
7889
7993
|
}
|
|
7890
7994
|
;
|
|
7891
7995
|
/**
|
|
7892
|
-
* Handles ping events during scheduled signal monitoring.
|
|
7996
|
+
* Handles scheduled ping events during scheduled signal monitoring.
|
|
7997
|
+
*/
|
|
7998
|
+
async pingScheduled(event) {
|
|
7999
|
+
this.params.logger.debug("ClientAction pingScheduled", {
|
|
8000
|
+
actionName: this.params.actionName,
|
|
8001
|
+
strategyName: this.params.strategyName,
|
|
8002
|
+
frameName: this.params.frameName,
|
|
8003
|
+
});
|
|
8004
|
+
if (!this._handlerInstance) {
|
|
8005
|
+
await this.waitForInit();
|
|
8006
|
+
}
|
|
8007
|
+
// Call handler method if defined
|
|
8008
|
+
if (this._handlerInstance?.pingScheduled) {
|
|
8009
|
+
await this._handlerInstance.pingScheduled(event);
|
|
8010
|
+
}
|
|
8011
|
+
// Call callback if defined
|
|
8012
|
+
await CALL_PING_SCHEDULED_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
8013
|
+
}
|
|
8014
|
+
;
|
|
8015
|
+
/**
|
|
8016
|
+
* Handles active ping events during active pending signal monitoring.
|
|
7893
8017
|
*/
|
|
7894
|
-
async
|
|
7895
|
-
this.params.logger.debug("ClientAction
|
|
8018
|
+
async pingActive(event) {
|
|
8019
|
+
this.params.logger.debug("ClientAction pingActive", {
|
|
7896
8020
|
actionName: this.params.actionName,
|
|
7897
8021
|
strategyName: this.params.strategyName,
|
|
7898
8022
|
frameName: this.params.frameName,
|
|
@@ -7901,11 +8025,11 @@ class ClientAction {
|
|
|
7901
8025
|
await this.waitForInit();
|
|
7902
8026
|
}
|
|
7903
8027
|
// Call handler method if defined
|
|
7904
|
-
if (this._handlerInstance?.
|
|
7905
|
-
await this._handlerInstance.
|
|
8028
|
+
if (this._handlerInstance?.pingActive) {
|
|
8029
|
+
await this._handlerInstance.pingActive(event);
|
|
7906
8030
|
}
|
|
7907
8031
|
// Call callback if defined
|
|
7908
|
-
await
|
|
8032
|
+
await CALL_PING_ACTIVE_CALLBACK_FN(this, event, this.params.strategyName, this.params.frameName, event.backtest);
|
|
7909
8033
|
}
|
|
7910
8034
|
;
|
|
7911
8035
|
/**
|
|
@@ -8073,13 +8197,13 @@ class ActionConnectionService {
|
|
|
8073
8197
|
* @param backtest - Whether running in backtest mode
|
|
8074
8198
|
* @param context - Execution context with action name, strategy name, exchange name, frame name
|
|
8075
8199
|
*/
|
|
8076
|
-
this.
|
|
8077
|
-
this.loggerService.log("actionConnectionService
|
|
8200
|
+
this.breakevenAvailable = async (event, backtest, context) => {
|
|
8201
|
+
this.loggerService.log("actionConnectionService breakevenAvailable", {
|
|
8078
8202
|
backtest,
|
|
8079
8203
|
context,
|
|
8080
8204
|
});
|
|
8081
8205
|
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
8082
|
-
await action.
|
|
8206
|
+
await action.breakevenAvailable(event);
|
|
8083
8207
|
};
|
|
8084
8208
|
/**
|
|
8085
8209
|
* Routes partialProfit event to appropriate ClientAction instance.
|
|
@@ -8088,13 +8212,13 @@ class ActionConnectionService {
|
|
|
8088
8212
|
* @param backtest - Whether running in backtest mode
|
|
8089
8213
|
* @param context - Execution context with action name, strategy name, exchange name, frame name
|
|
8090
8214
|
*/
|
|
8091
|
-
this.
|
|
8092
|
-
this.loggerService.log("actionConnectionService
|
|
8215
|
+
this.partialProfitAvailable = async (event, backtest, context) => {
|
|
8216
|
+
this.loggerService.log("actionConnectionService partialProfitAvailable", {
|
|
8093
8217
|
backtest,
|
|
8094
8218
|
context,
|
|
8095
8219
|
});
|
|
8096
8220
|
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
8097
|
-
await action.
|
|
8221
|
+
await action.partialProfitAvailable(event);
|
|
8098
8222
|
};
|
|
8099
8223
|
/**
|
|
8100
8224
|
* Routes partialLoss event to appropriate ClientAction instance.
|
|
@@ -8103,28 +8227,43 @@ class ActionConnectionService {
|
|
|
8103
8227
|
* @param backtest - Whether running in backtest mode
|
|
8104
8228
|
* @param context - Execution context with action name, strategy name, exchange name, frame name
|
|
8105
8229
|
*/
|
|
8106
|
-
this.
|
|
8107
|
-
this.loggerService.log("actionConnectionService
|
|
8230
|
+
this.partialLossAvailable = async (event, backtest, context) => {
|
|
8231
|
+
this.loggerService.log("actionConnectionService partialLossAvailable", {
|
|
8232
|
+
backtest,
|
|
8233
|
+
context,
|
|
8234
|
+
});
|
|
8235
|
+
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
8236
|
+
await action.partialLossAvailable(event);
|
|
8237
|
+
};
|
|
8238
|
+
/**
|
|
8239
|
+
* Routes scheduled ping event to appropriate ClientAction instance.
|
|
8240
|
+
*
|
|
8241
|
+
* @param event - Scheduled ping event data
|
|
8242
|
+
* @param backtest - Whether running in backtest mode
|
|
8243
|
+
* @param context - Execution context with action name, strategy name, exchange name, frame name
|
|
8244
|
+
*/
|
|
8245
|
+
this.pingScheduled = async (event, backtest, context) => {
|
|
8246
|
+
this.loggerService.log("actionConnectionService pingScheduled", {
|
|
8108
8247
|
backtest,
|
|
8109
8248
|
context,
|
|
8110
8249
|
});
|
|
8111
8250
|
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
8112
|
-
await action.
|
|
8251
|
+
await action.pingScheduled(event);
|
|
8113
8252
|
};
|
|
8114
8253
|
/**
|
|
8115
|
-
* Routes ping event to appropriate ClientAction instance.
|
|
8254
|
+
* Routes active ping event to appropriate ClientAction instance.
|
|
8116
8255
|
*
|
|
8117
|
-
* @param event -
|
|
8256
|
+
* @param event - Active ping event data
|
|
8118
8257
|
* @param backtest - Whether running in backtest mode
|
|
8119
8258
|
* @param context - Execution context with action name, strategy name, exchange name, frame name
|
|
8120
8259
|
*/
|
|
8121
|
-
this.
|
|
8122
|
-
this.loggerService.log("actionConnectionService
|
|
8260
|
+
this.pingActive = async (event, backtest, context) => {
|
|
8261
|
+
this.loggerService.log("actionConnectionService pingActive", {
|
|
8123
8262
|
backtest,
|
|
8124
8263
|
context,
|
|
8125
8264
|
});
|
|
8126
8265
|
const action = this.getAction(context.actionName, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
8127
|
-
await action.
|
|
8266
|
+
await action.pingActive(event);
|
|
8128
8267
|
};
|
|
8129
8268
|
/**
|
|
8130
8269
|
* Routes riskRejection event to appropriate ClientAction instance.
|
|
@@ -9188,81 +9327,102 @@ class ActionCoreService {
|
|
|
9188
9327
|
* Routes breakeven event to all registered actions for the strategy.
|
|
9189
9328
|
*
|
|
9190
9329
|
* Retrieves action list from strategy schema (IStrategySchema.actions)
|
|
9191
|
-
* and invokes the
|
|
9330
|
+
* and invokes the breakevenAvailable handler on each ClientAction instance sequentially.
|
|
9192
9331
|
*
|
|
9193
9332
|
* @param backtest - Whether running in backtest mode (true) or live mode (false)
|
|
9194
9333
|
* @param event - Breakeven milestone data (stop-loss moved to entry price)
|
|
9195
9334
|
* @param context - Strategy execution context with strategyName, exchangeName, frameName
|
|
9196
9335
|
*/
|
|
9197
|
-
this.
|
|
9198
|
-
this.loggerService.log("actionCoreService
|
|
9336
|
+
this.breakevenAvailable = async (backtest, event, context) => {
|
|
9337
|
+
this.loggerService.log("actionCoreService breakevenAvailable", {
|
|
9199
9338
|
context,
|
|
9200
9339
|
});
|
|
9201
9340
|
await this.validate(context);
|
|
9202
9341
|
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
9203
9342
|
for (const actionName of actions) {
|
|
9204
|
-
await this.actionConnectionService.
|
|
9343
|
+
await this.actionConnectionService.breakevenAvailable(event, backtest, { actionName, ...context });
|
|
9205
9344
|
}
|
|
9206
9345
|
};
|
|
9207
9346
|
/**
|
|
9208
9347
|
* Routes partial profit event to all registered actions for the strategy.
|
|
9209
9348
|
*
|
|
9210
9349
|
* Retrieves action list from strategy schema (IStrategySchema.actions)
|
|
9211
|
-
* and invokes the
|
|
9350
|
+
* and invokes the partialProfitAvailable handler on each ClientAction instance sequentially.
|
|
9212
9351
|
*
|
|
9213
9352
|
* @param backtest - Whether running in backtest mode (true) or live mode (false)
|
|
9214
9353
|
* @param event - Profit milestone data with level (10%, 20%, etc.) and price
|
|
9215
9354
|
* @param context - Strategy execution context with strategyName, exchangeName, frameName
|
|
9216
9355
|
*/
|
|
9217
|
-
this.
|
|
9218
|
-
this.loggerService.log("actionCoreService
|
|
9356
|
+
this.partialProfitAvailable = async (backtest, event, context) => {
|
|
9357
|
+
this.loggerService.log("actionCoreService partialProfitAvailable", {
|
|
9219
9358
|
context,
|
|
9220
9359
|
});
|
|
9221
9360
|
await this.validate(context);
|
|
9222
9361
|
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
9223
9362
|
for (const actionName of actions) {
|
|
9224
|
-
await this.actionConnectionService.
|
|
9363
|
+
await this.actionConnectionService.partialProfitAvailable(event, backtest, { actionName, ...context });
|
|
9225
9364
|
}
|
|
9226
9365
|
};
|
|
9227
9366
|
/**
|
|
9228
9367
|
* Routes partial loss event to all registered actions for the strategy.
|
|
9229
9368
|
*
|
|
9230
9369
|
* Retrieves action list from strategy schema (IStrategySchema.actions)
|
|
9231
|
-
* and invokes the
|
|
9370
|
+
* and invokes the partialLossAvailable handler on each ClientAction instance sequentially.
|
|
9232
9371
|
*
|
|
9233
9372
|
* @param backtest - Whether running in backtest mode (true) or live mode (false)
|
|
9234
9373
|
* @param event - Loss milestone data with level (-10%, -20%, etc.) and price
|
|
9235
9374
|
* @param context - Strategy execution context with strategyName, exchangeName, frameName
|
|
9236
9375
|
*/
|
|
9237
|
-
this.
|
|
9238
|
-
this.loggerService.log("actionCoreService
|
|
9376
|
+
this.partialLossAvailable = async (backtest, event, context) => {
|
|
9377
|
+
this.loggerService.log("actionCoreService partialLossAvailable", {
|
|
9239
9378
|
context,
|
|
9240
9379
|
});
|
|
9241
9380
|
await this.validate(context);
|
|
9242
9381
|
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
9243
9382
|
for (const actionName of actions) {
|
|
9244
|
-
await this.actionConnectionService.
|
|
9383
|
+
await this.actionConnectionService.partialLossAvailable(event, backtest, { actionName, ...context });
|
|
9245
9384
|
}
|
|
9246
9385
|
};
|
|
9247
9386
|
/**
|
|
9248
|
-
* Routes ping event to all registered actions for the strategy.
|
|
9387
|
+
* Routes scheduled ping event to all registered actions for the strategy.
|
|
9249
9388
|
*
|
|
9250
9389
|
* Retrieves action list from strategy schema (IStrategySchema.actions)
|
|
9251
|
-
* and invokes the
|
|
9390
|
+
* and invokes the pingScheduled handler on each ClientAction instance sequentially.
|
|
9252
9391
|
* Called every minute during scheduled signal monitoring.
|
|
9253
9392
|
*
|
|
9254
9393
|
* @param backtest - Whether running in backtest mode (true) or live mode (false)
|
|
9255
9394
|
* @param event - Scheduled signal monitoring data
|
|
9256
9395
|
* @param context - Strategy execution context with strategyName, exchangeName, frameName
|
|
9257
9396
|
*/
|
|
9258
|
-
this.
|
|
9259
|
-
this.loggerService.log("actionCoreService
|
|
9397
|
+
this.pingScheduled = async (backtest, event, context) => {
|
|
9398
|
+
this.loggerService.log("actionCoreService pingScheduled", {
|
|
9399
|
+
context,
|
|
9400
|
+
});
|
|
9401
|
+
await this.validate(context);
|
|
9402
|
+
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
9403
|
+
for (const actionName of actions) {
|
|
9404
|
+
await this.actionConnectionService.pingScheduled(event, backtest, { actionName, ...context });
|
|
9405
|
+
}
|
|
9406
|
+
};
|
|
9407
|
+
/**
|
|
9408
|
+
* Routes active ping event to all registered actions for the strategy.
|
|
9409
|
+
*
|
|
9410
|
+
* Retrieves action list from strategy schema (IStrategySchema.actions)
|
|
9411
|
+
* and invokes the pingActive handler on each ClientAction instance sequentially.
|
|
9412
|
+
* Called every minute during active pending signal monitoring.
|
|
9413
|
+
*
|
|
9414
|
+
* @param backtest - Whether running in backtest mode (true) or live mode (false)
|
|
9415
|
+
* @param event - Active pending signal monitoring data
|
|
9416
|
+
* @param context - Strategy execution context with strategyName, exchangeName, frameName
|
|
9417
|
+
*/
|
|
9418
|
+
this.pingActive = async (backtest, event, context) => {
|
|
9419
|
+
this.loggerService.log("actionCoreService pingActive", {
|
|
9260
9420
|
context,
|
|
9261
9421
|
});
|
|
9262
9422
|
await this.validate(context);
|
|
9263
9423
|
const { actions = [] } = this.strategySchemaService.get(context.strategyName);
|
|
9264
9424
|
for (const actionName of actions) {
|
|
9265
|
-
await this.actionConnectionService.
|
|
9425
|
+
await this.actionConnectionService.pingActive(event, backtest, { actionName, ...context });
|
|
9266
9426
|
}
|
|
9267
9427
|
};
|
|
9268
9428
|
/**
|
|
@@ -10381,7 +10541,11 @@ class LiveLogicPrivateService {
|
|
|
10381
10541
|
await functoolsKit.sleep(TICK_TTL);
|
|
10382
10542
|
continue;
|
|
10383
10543
|
}
|
|
10384
|
-
|
|
10544
|
+
if (result.action === "waiting") {
|
|
10545
|
+
await functoolsKit.sleep(TICK_TTL);
|
|
10546
|
+
continue;
|
|
10547
|
+
}
|
|
10548
|
+
// Yield opened, closed, cancelled results
|
|
10385
10549
|
yield result;
|
|
10386
10550
|
// Check if strategy should stop after signal is closed
|
|
10387
10551
|
if (result.action === "closed") {
|
|
@@ -12316,6 +12480,12 @@ var _a$1, _b$1;
|
|
|
12316
12480
|
const MARKDOWN_METHOD_NAME_ENABLE = "MarkdownUtils.enable";
|
|
12317
12481
|
const MARKDOWN_METHOD_NAME_DISABLE = "MarkdownUtils.disable";
|
|
12318
12482
|
const MARKDOWN_METHOD_NAME_USE_ADAPTER = "MarkdownAdapter.useMarkdownAdapter";
|
|
12483
|
+
const MARKDOWN_METHOD_NAME_FILE_DUMP = "MarkdownFileAdapter.dump";
|
|
12484
|
+
const MARKDOWN_METHOD_NAME_FOLDER_DUMP = "MarkdownFolderAdapter.dump";
|
|
12485
|
+
const MARKDOWN_METHOD_NAME_WRITE_DATA = "MarkdownAdapter.writeData";
|
|
12486
|
+
const MARKDOWN_METHOD_NAME_USE_MD = "MarkdownAdapter.useMd";
|
|
12487
|
+
const MARKDOWN_METHOD_NAME_USE_JSONL = "MarkdownAdapter.useJsonl";
|
|
12488
|
+
const MARKDOWN_METHOD_NAME_USE_DUMMY = "MarkdownAdapter.useDummy";
|
|
12319
12489
|
const WAIT_FOR_INIT_SYMBOL$1 = Symbol("wait-for-init");
|
|
12320
12490
|
const WRITE_SAFE_SYMBOL$1 = Symbol("write-safe");
|
|
12321
12491
|
/**
|
|
@@ -12409,7 +12579,7 @@ class MarkdownFileBase {
|
|
|
12409
12579
|
* @throws Error if stream not initialized or write timeout exceeded
|
|
12410
12580
|
*/
|
|
12411
12581
|
async dump(data, options) {
|
|
12412
|
-
backtest$1.loggerService.debug(
|
|
12582
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_FILE_DUMP, {
|
|
12413
12583
|
markdownName: this.markdownName,
|
|
12414
12584
|
options,
|
|
12415
12585
|
});
|
|
@@ -12491,7 +12661,7 @@ class MarkdownFolderBase {
|
|
|
12491
12661
|
* @throws Error if directory creation or file write fails
|
|
12492
12662
|
*/
|
|
12493
12663
|
async dump(content, options) {
|
|
12494
|
-
backtest$1.loggerService.debug(
|
|
12664
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_FOLDER_DUMP, {
|
|
12495
12665
|
markdownName: this.markdownName,
|
|
12496
12666
|
options,
|
|
12497
12667
|
});
|
|
@@ -12731,7 +12901,7 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
12731
12901
|
* @internal - Use service-specific dump methods instead (e.g., Backtest.dump)
|
|
12732
12902
|
*/
|
|
12733
12903
|
async writeData(markdownName, content, options) {
|
|
12734
|
-
backtest$1.loggerService.debug(
|
|
12904
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_WRITE_DATA, {
|
|
12735
12905
|
markdownName,
|
|
12736
12906
|
options,
|
|
12737
12907
|
});
|
|
@@ -12746,7 +12916,7 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
12746
12916
|
* Each dump creates a separate .md file.
|
|
12747
12917
|
*/
|
|
12748
12918
|
useMd() {
|
|
12749
|
-
backtest$1.loggerService.debug(
|
|
12919
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_MD);
|
|
12750
12920
|
this.useMarkdownAdapter(MarkdownFolderBase);
|
|
12751
12921
|
}
|
|
12752
12922
|
/**
|
|
@@ -12755,7 +12925,7 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
12755
12925
|
* All dumps append to a single .jsonl file per markdown type.
|
|
12756
12926
|
*/
|
|
12757
12927
|
useJsonl() {
|
|
12758
|
-
backtest$1.loggerService.debug(
|
|
12928
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_JSONL);
|
|
12759
12929
|
this.useMarkdownAdapter(MarkdownFileBase);
|
|
12760
12930
|
}
|
|
12761
12931
|
/**
|
|
@@ -12763,7 +12933,7 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
12763
12933
|
* All future markdown writes will be no-ops.
|
|
12764
12934
|
*/
|
|
12765
12935
|
useDummy() {
|
|
12766
|
-
backtest$1.loggerService.debug(
|
|
12936
|
+
backtest$1.loggerService.debug(MARKDOWN_METHOD_NAME_USE_DUMMY);
|
|
12767
12937
|
this.useMarkdownAdapter(MarkdownDummy);
|
|
12768
12938
|
}
|
|
12769
12939
|
}
|
|
@@ -13426,6 +13596,98 @@ let ReportStorage$5 = class ReportStorage {
|
|
|
13426
13596
|
this._eventList.pop();
|
|
13427
13597
|
}
|
|
13428
13598
|
}
|
|
13599
|
+
/**
|
|
13600
|
+
* Adds a scheduled event to the storage.
|
|
13601
|
+
*
|
|
13602
|
+
* @param data - Scheduled tick result
|
|
13603
|
+
*/
|
|
13604
|
+
addScheduledEvent(data) {
|
|
13605
|
+
this._eventList.unshift({
|
|
13606
|
+
timestamp: data.signal.scheduledAt,
|
|
13607
|
+
action: "scheduled",
|
|
13608
|
+
symbol: data.signal.symbol,
|
|
13609
|
+
signalId: data.signal.id,
|
|
13610
|
+
position: data.signal.position,
|
|
13611
|
+
note: data.signal.note,
|
|
13612
|
+
currentPrice: data.currentPrice,
|
|
13613
|
+
priceOpen: data.signal.priceOpen,
|
|
13614
|
+
priceTakeProfit: data.signal.priceTakeProfit,
|
|
13615
|
+
priceStopLoss: data.signal.priceStopLoss,
|
|
13616
|
+
originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
|
|
13617
|
+
originalPriceStopLoss: data.signal.originalPriceStopLoss,
|
|
13618
|
+
totalExecuted: data.signal.totalExecuted,
|
|
13619
|
+
});
|
|
13620
|
+
// Trim queue if exceeded MAX_EVENTS
|
|
13621
|
+
if (this._eventList.length > MAX_EVENTS$6) {
|
|
13622
|
+
this._eventList.pop();
|
|
13623
|
+
}
|
|
13624
|
+
}
|
|
13625
|
+
/**
|
|
13626
|
+
* Adds a waiting event to the storage.
|
|
13627
|
+
* Replaces the last waiting event with the same signalId.
|
|
13628
|
+
*
|
|
13629
|
+
* @param data - Waiting tick result
|
|
13630
|
+
*/
|
|
13631
|
+
addWaitingEvent(data) {
|
|
13632
|
+
const newEvent = {
|
|
13633
|
+
timestamp: Date.now(),
|
|
13634
|
+
action: "waiting",
|
|
13635
|
+
symbol: data.signal.symbol,
|
|
13636
|
+
signalId: data.signal.id,
|
|
13637
|
+
position: data.signal.position,
|
|
13638
|
+
note: data.signal.note,
|
|
13639
|
+
currentPrice: data.currentPrice,
|
|
13640
|
+
priceOpen: data.signal.priceOpen,
|
|
13641
|
+
priceTakeProfit: data.signal.priceTakeProfit,
|
|
13642
|
+
priceStopLoss: data.signal.priceStopLoss,
|
|
13643
|
+
originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
|
|
13644
|
+
originalPriceStopLoss: data.signal.originalPriceStopLoss,
|
|
13645
|
+
totalExecuted: data.signal.totalExecuted,
|
|
13646
|
+
percentTp: data.percentTp,
|
|
13647
|
+
percentSl: data.percentSl,
|
|
13648
|
+
pnl: data.pnl.pnlPercentage,
|
|
13649
|
+
};
|
|
13650
|
+
// Find the last waiting event with the same signalId
|
|
13651
|
+
const lastWaitingIndex = this._eventList.findLastIndex((event) => event.action === "waiting" && event.signalId === data.signal.id);
|
|
13652
|
+
// Replace the last waiting event with the same signalId
|
|
13653
|
+
if (lastWaitingIndex !== -1) {
|
|
13654
|
+
this._eventList[lastWaitingIndex] = newEvent;
|
|
13655
|
+
return;
|
|
13656
|
+
}
|
|
13657
|
+
// If no previous waiting event found, add new event
|
|
13658
|
+
this._eventList.unshift(newEvent);
|
|
13659
|
+
// Trim queue if exceeded MAX_EVENTS
|
|
13660
|
+
if (this._eventList.length > MAX_EVENTS$6) {
|
|
13661
|
+
this._eventList.pop();
|
|
13662
|
+
}
|
|
13663
|
+
}
|
|
13664
|
+
/**
|
|
13665
|
+
* Adds a cancelled event to the storage.
|
|
13666
|
+
*
|
|
13667
|
+
* @param data - Cancelled tick result
|
|
13668
|
+
*/
|
|
13669
|
+
addCancelledEvent(data) {
|
|
13670
|
+
this._eventList.unshift({
|
|
13671
|
+
timestamp: data.closeTimestamp,
|
|
13672
|
+
action: "cancelled",
|
|
13673
|
+
symbol: data.signal.symbol,
|
|
13674
|
+
signalId: data.signal.id,
|
|
13675
|
+
position: data.signal.position,
|
|
13676
|
+
note: data.signal.note,
|
|
13677
|
+
currentPrice: data.currentPrice,
|
|
13678
|
+
priceOpen: data.signal.priceOpen,
|
|
13679
|
+
priceTakeProfit: data.signal.priceTakeProfit,
|
|
13680
|
+
priceStopLoss: data.signal.priceStopLoss,
|
|
13681
|
+
originalPriceTakeProfit: data.signal.originalPriceTakeProfit,
|
|
13682
|
+
originalPriceStopLoss: data.signal.originalPriceStopLoss,
|
|
13683
|
+
totalExecuted: data.signal.totalExecuted,
|
|
13684
|
+
cancelReason: data.reason,
|
|
13685
|
+
});
|
|
13686
|
+
// Trim queue if exceeded MAX_EVENTS
|
|
13687
|
+
if (this._eventList.length > MAX_EVENTS$6) {
|
|
13688
|
+
this._eventList.pop();
|
|
13689
|
+
}
|
|
13690
|
+
}
|
|
13429
13691
|
/**
|
|
13430
13692
|
* Calculates statistical data from live trading events (Controller).
|
|
13431
13693
|
* Returns null for any unsafe numeric values (NaN, Infinity, etc).
|
|
@@ -13683,6 +13945,12 @@ class LiveMarkdownService {
|
|
|
13683
13945
|
if (data.action === "idle") {
|
|
13684
13946
|
storage.addIdleEvent(data.currentPrice);
|
|
13685
13947
|
}
|
|
13948
|
+
else if (data.action === "scheduled") {
|
|
13949
|
+
storage.addScheduledEvent(data);
|
|
13950
|
+
}
|
|
13951
|
+
else if (data.action === "waiting") {
|
|
13952
|
+
storage.addWaitingEvent(data);
|
|
13953
|
+
}
|
|
13686
13954
|
else if (data.action === "opened") {
|
|
13687
13955
|
storage.addOpenedEvent(data);
|
|
13688
13956
|
}
|
|
@@ -13692,6 +13960,9 @@ class LiveMarkdownService {
|
|
|
13692
13960
|
else if (data.action === "closed") {
|
|
13693
13961
|
storage.addClosedEvent(data);
|
|
13694
13962
|
}
|
|
13963
|
+
else if (data.action === "cancelled") {
|
|
13964
|
+
storage.addCancelledEvent(data);
|
|
13965
|
+
}
|
|
13695
13966
|
};
|
|
13696
13967
|
/**
|
|
13697
13968
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
@@ -18118,7 +18389,7 @@ const CREATE_COMMIT_PROFIT_FN = (self) => async (symbol, strategyName, exchangeN
|
|
|
18118
18389
|
timestamp,
|
|
18119
18390
|
};
|
|
18120
18391
|
await partialProfitSubject.next(event);
|
|
18121
|
-
await self.actionCoreService.
|
|
18392
|
+
await self.actionCoreService.partialProfitAvailable(backtest, event, { strategyName, exchangeName, frameName });
|
|
18122
18393
|
};
|
|
18123
18394
|
/**
|
|
18124
18395
|
* Creates a callback function for emitting loss events to partialLossSubject.
|
|
@@ -18142,7 +18413,7 @@ const CREATE_COMMIT_LOSS_FN = (self) => async (symbol, strategyName, exchangeNam
|
|
|
18142
18413
|
timestamp,
|
|
18143
18414
|
};
|
|
18144
18415
|
await partialLossSubject.next(event);
|
|
18145
|
-
await self.actionCoreService.
|
|
18416
|
+
await self.actionCoreService.partialLossAvailable(backtest, event, { strategyName, exchangeName, frameName });
|
|
18146
18417
|
};
|
|
18147
18418
|
/**
|
|
18148
18419
|
* Connection service for partial profit/loss tracking.
|
|
@@ -19291,7 +19562,7 @@ const CREATE_COMMIT_BREAKEVEN_FN = (self) => async (symbol, strategyName, exchan
|
|
|
19291
19562
|
timestamp,
|
|
19292
19563
|
};
|
|
19293
19564
|
await breakevenSubject.next(event);
|
|
19294
|
-
await self.actionCoreService.
|
|
19565
|
+
await self.actionCoreService.breakevenAvailable(backtest, event, { strategyName, exchangeName, frameName });
|
|
19295
19566
|
};
|
|
19296
19567
|
/**
|
|
19297
19568
|
* Connection service for breakeven tracking.
|
|
@@ -21376,6 +21647,43 @@ class LiveReportService {
|
|
|
21376
21647
|
if (data.action === "idle") {
|
|
21377
21648
|
await Report.writeData("live", baseEvent, searchOptions);
|
|
21378
21649
|
}
|
|
21650
|
+
else if (data.action === "scheduled") {
|
|
21651
|
+
await Report.writeData("live", {
|
|
21652
|
+
...baseEvent,
|
|
21653
|
+
signalId: data.signal?.id,
|
|
21654
|
+
position: data.signal?.position,
|
|
21655
|
+
note: data.signal?.note,
|
|
21656
|
+
priceOpen: data.signal?.priceOpen,
|
|
21657
|
+
priceTakeProfit: data.signal?.priceTakeProfit,
|
|
21658
|
+
priceStopLoss: data.signal?.priceStopLoss,
|
|
21659
|
+
originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
|
|
21660
|
+
originalPriceStopLoss: data.signal?.originalPriceStopLoss,
|
|
21661
|
+
totalExecuted: data.signal?.totalExecuted,
|
|
21662
|
+
scheduledAt: data.signal?.scheduledAt,
|
|
21663
|
+
minuteEstimatedTime: data.signal?.minuteEstimatedTime,
|
|
21664
|
+
}, { ...searchOptions, signalId: data.signal?.id });
|
|
21665
|
+
}
|
|
21666
|
+
else if (data.action === "waiting") {
|
|
21667
|
+
await Report.writeData("live", {
|
|
21668
|
+
...baseEvent,
|
|
21669
|
+
signalId: data.signal?.id,
|
|
21670
|
+
position: data.signal?.position,
|
|
21671
|
+
note: data.signal?.note,
|
|
21672
|
+
priceOpen: data.signal?.priceOpen,
|
|
21673
|
+
priceTakeProfit: data.signal?.priceTakeProfit,
|
|
21674
|
+
priceStopLoss: data.signal?.priceStopLoss,
|
|
21675
|
+
originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
|
|
21676
|
+
originalPriceStopLoss: data.signal?.originalPriceStopLoss,
|
|
21677
|
+
totalExecuted: data.signal?.totalExecuted,
|
|
21678
|
+
scheduledAt: data.signal?.scheduledAt,
|
|
21679
|
+
minuteEstimatedTime: data.signal?.minuteEstimatedTime,
|
|
21680
|
+
percentTp: data.percentTp,
|
|
21681
|
+
percentSl: data.percentSl,
|
|
21682
|
+
pnl: data.pnl.pnlPercentage,
|
|
21683
|
+
pnlPriceOpen: data.pnl.priceOpen,
|
|
21684
|
+
pnlPriceClose: data.pnl.priceClose,
|
|
21685
|
+
}, { ...searchOptions, signalId: data.signal?.id });
|
|
21686
|
+
}
|
|
21379
21687
|
else if (data.action === "opened") {
|
|
21380
21688
|
await Report.writeData("live", {
|
|
21381
21689
|
...baseEvent,
|
|
@@ -21442,6 +21750,24 @@ class LiveReportService {
|
|
|
21442
21750
|
closeTime: data.closeTimestamp,
|
|
21443
21751
|
}, { ...searchOptions, signalId: data.signal?.id });
|
|
21444
21752
|
}
|
|
21753
|
+
else if (data.action === "cancelled") {
|
|
21754
|
+
await Report.writeData("live", {
|
|
21755
|
+
...baseEvent,
|
|
21756
|
+
signalId: data.signal?.id,
|
|
21757
|
+
position: data.signal?.position,
|
|
21758
|
+
note: data.signal?.note,
|
|
21759
|
+
priceOpen: data.signal?.priceOpen,
|
|
21760
|
+
priceTakeProfit: data.signal?.priceTakeProfit,
|
|
21761
|
+
priceStopLoss: data.signal?.priceStopLoss,
|
|
21762
|
+
originalPriceTakeProfit: data.signal?.originalPriceTakeProfit,
|
|
21763
|
+
originalPriceStopLoss: data.signal?.originalPriceStopLoss,
|
|
21764
|
+
totalExecuted: data.signal?.totalExecuted,
|
|
21765
|
+
scheduledAt: data.signal?.scheduledAt,
|
|
21766
|
+
minuteEstimatedTime: data.signal?.minuteEstimatedTime,
|
|
21767
|
+
cancelReason: data.reason,
|
|
21768
|
+
closeTime: data.closeTimestamp,
|
|
21769
|
+
}, { ...searchOptions, signalId: data.signal?.id });
|
|
21770
|
+
}
|
|
21445
21771
|
};
|
|
21446
21772
|
/**
|
|
21447
21773
|
* Subscribes to live signal emitter to receive tick events.
|
|
@@ -22631,6 +22957,27 @@ const backtest = {
|
|
|
22631
22957
|
init();
|
|
22632
22958
|
var backtest$1 = backtest;
|
|
22633
22959
|
|
|
22960
|
+
const GET_TIMEFRAME_METHOD_NAME = "get.getBacktestTimeframe";
|
|
22961
|
+
/**
|
|
22962
|
+
* Retrieves current backtest timeframe for given symbol.
|
|
22963
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
22964
|
+
* @returns Promise resolving to array of Date objects representing tick timestamps
|
|
22965
|
+
* @throws Error if called outside of backtest execution context
|
|
22966
|
+
*/
|
|
22967
|
+
async function getBacktestTimeframe(symbol) {
|
|
22968
|
+
backtest$1.loggerService.info(GET_TIMEFRAME_METHOD_NAME, { symbol });
|
|
22969
|
+
if (!ExecutionContextService.hasContext()) {
|
|
22970
|
+
throw new Error("getBacktestTimeframe requires an execution context");
|
|
22971
|
+
}
|
|
22972
|
+
if (!MethodContextService.hasContext()) {
|
|
22973
|
+
throw new Error("getBacktestTimeframe requires a method context");
|
|
22974
|
+
}
|
|
22975
|
+
if (!backtest$1.executionContextService.context.backtest) {
|
|
22976
|
+
throw new Error("getBacktestTimeframe can only be used during backtest execution");
|
|
22977
|
+
}
|
|
22978
|
+
return await backtest$1.frameCoreService.getTimeframe(symbol, backtest$1.methodContextService.context.frameName);
|
|
22979
|
+
}
|
|
22980
|
+
|
|
22634
22981
|
const METHOD_NAME = "validate.validate";
|
|
22635
22982
|
/**
|
|
22636
22983
|
* Retrieves all registered exchanges as a map
|
|
@@ -22826,12 +23173,197 @@ async function validate(args = {}) {
|
|
|
22826
23173
|
return await validateInternal(args);
|
|
22827
23174
|
}
|
|
22828
23175
|
|
|
23176
|
+
const GET_STRATEGY_METHOD_NAME = "get.getStrategySchema";
|
|
23177
|
+
const GET_EXCHANGE_METHOD_NAME = "get.getExchangeSchema";
|
|
23178
|
+
const GET_FRAME_METHOD_NAME = "get.getFrameSchema";
|
|
23179
|
+
const GET_WALKER_METHOD_NAME = "get.getWalkerSchema";
|
|
23180
|
+
const GET_SIZING_METHOD_NAME = "get.getSizingSchema";
|
|
23181
|
+
const GET_RISK_METHOD_NAME = "get.getRiskSchema";
|
|
23182
|
+
const GET_OPTIMIZER_METHOD_NAME = "get.getOptimizerSchema";
|
|
23183
|
+
const GET_ACTION_METHOD_NAME = "get.getActionSchema";
|
|
23184
|
+
/**
|
|
23185
|
+
* Retrieves a registered strategy schema by name.
|
|
23186
|
+
*
|
|
23187
|
+
* @param strategyName - Unique strategy identifier
|
|
23188
|
+
* @returns The strategy schema configuration object
|
|
23189
|
+
* @throws Error if strategy is not registered
|
|
23190
|
+
*
|
|
23191
|
+
* @example
|
|
23192
|
+
* ```typescript
|
|
23193
|
+
* const strategy = getStrategy("my-strategy");
|
|
23194
|
+
* console.log(strategy.interval); // "5m"
|
|
23195
|
+
* console.log(strategy.getSignal); // async function
|
|
23196
|
+
* ```
|
|
23197
|
+
*/
|
|
23198
|
+
function getStrategySchema(strategyName) {
|
|
23199
|
+
backtest$1.loggerService.log(GET_STRATEGY_METHOD_NAME, {
|
|
23200
|
+
strategyName,
|
|
23201
|
+
});
|
|
23202
|
+
backtest$1.strategyValidationService.validate(strategyName, GET_STRATEGY_METHOD_NAME);
|
|
23203
|
+
return backtest$1.strategySchemaService.get(strategyName);
|
|
23204
|
+
}
|
|
23205
|
+
/**
|
|
23206
|
+
* Retrieves a registered exchange schema by name.
|
|
23207
|
+
*
|
|
23208
|
+
* @param exchangeName - Unique exchange identifier
|
|
23209
|
+
* @returns The exchange schema configuration object
|
|
23210
|
+
* @throws Error if exchange is not registered
|
|
23211
|
+
*
|
|
23212
|
+
* @example
|
|
23213
|
+
* ```typescript
|
|
23214
|
+
* const exchange = getExchange("binance");
|
|
23215
|
+
* console.log(exchange.getCandles); // async function
|
|
23216
|
+
* console.log(exchange.formatPrice); // async function
|
|
23217
|
+
* ```
|
|
23218
|
+
*/
|
|
23219
|
+
function getExchangeSchema(exchangeName) {
|
|
23220
|
+
backtest$1.loggerService.log(GET_EXCHANGE_METHOD_NAME, {
|
|
23221
|
+
exchangeName,
|
|
23222
|
+
});
|
|
23223
|
+
backtest$1.exchangeValidationService.validate(exchangeName, GET_EXCHANGE_METHOD_NAME);
|
|
23224
|
+
return backtest$1.exchangeSchemaService.get(exchangeName);
|
|
23225
|
+
}
|
|
23226
|
+
/**
|
|
23227
|
+
* Retrieves a registered frame schema by name.
|
|
23228
|
+
*
|
|
23229
|
+
* @param frameName - Unique frame identifier
|
|
23230
|
+
* @returns The frame schema configuration object
|
|
23231
|
+
* @throws Error if frame is not registered
|
|
23232
|
+
*
|
|
23233
|
+
* @example
|
|
23234
|
+
* ```typescript
|
|
23235
|
+
* const frame = getFrame("1d-backtest");
|
|
23236
|
+
* console.log(frame.interval); // "1m"
|
|
23237
|
+
* console.log(frame.startDate); // Date object
|
|
23238
|
+
* console.log(frame.endDate); // Date object
|
|
23239
|
+
* ```
|
|
23240
|
+
*/
|
|
23241
|
+
function getFrameSchema(frameName) {
|
|
23242
|
+
backtest$1.loggerService.log(GET_FRAME_METHOD_NAME, {
|
|
23243
|
+
frameName,
|
|
23244
|
+
});
|
|
23245
|
+
backtest$1.frameValidationService.validate(frameName, GET_FRAME_METHOD_NAME);
|
|
23246
|
+
return backtest$1.frameSchemaService.get(frameName);
|
|
23247
|
+
}
|
|
23248
|
+
/**
|
|
23249
|
+
* Retrieves a registered walker schema by name.
|
|
23250
|
+
*
|
|
23251
|
+
* @param walkerName - Unique walker identifier
|
|
23252
|
+
* @returns The walker schema configuration object
|
|
23253
|
+
* @throws Error if walker is not registered
|
|
23254
|
+
*
|
|
23255
|
+
* @example
|
|
23256
|
+
* ```typescript
|
|
23257
|
+
* const walker = getWalker("llm-prompt-optimizer");
|
|
23258
|
+
* console.log(walker.exchangeName); // "binance"
|
|
23259
|
+
* console.log(walker.frameName); // "1d-backtest"
|
|
23260
|
+
* console.log(walker.strategies); // ["my-strategy-v1", "my-strategy-v2"]
|
|
23261
|
+
* console.log(walker.metric); // "sharpeRatio"
|
|
23262
|
+
* ```
|
|
23263
|
+
*/
|
|
23264
|
+
function getWalkerSchema(walkerName) {
|
|
23265
|
+
backtest$1.loggerService.log(GET_WALKER_METHOD_NAME, {
|
|
23266
|
+
walkerName,
|
|
23267
|
+
});
|
|
23268
|
+
backtest$1.walkerValidationService.validate(walkerName, GET_WALKER_METHOD_NAME);
|
|
23269
|
+
return backtest$1.walkerSchemaService.get(walkerName);
|
|
23270
|
+
}
|
|
23271
|
+
/**
|
|
23272
|
+
* Retrieves a registered sizing schema by name.
|
|
23273
|
+
*
|
|
23274
|
+
* @param sizingName - Unique sizing identifier
|
|
23275
|
+
* @returns The sizing schema configuration object
|
|
23276
|
+
* @throws Error if sizing is not registered
|
|
23277
|
+
*
|
|
23278
|
+
* @example
|
|
23279
|
+
* ```typescript
|
|
23280
|
+
* const sizing = getSizing("conservative");
|
|
23281
|
+
* console.log(sizing.method); // "fixed-percentage"
|
|
23282
|
+
* console.log(sizing.riskPercentage); // 1
|
|
23283
|
+
* console.log(sizing.maxPositionPercentage); // 10
|
|
23284
|
+
* ```
|
|
23285
|
+
*/
|
|
23286
|
+
function getSizingSchema(sizingName) {
|
|
23287
|
+
backtest$1.loggerService.log(GET_SIZING_METHOD_NAME, {
|
|
23288
|
+
sizingName,
|
|
23289
|
+
});
|
|
23290
|
+
backtest$1.sizingValidationService.validate(sizingName, GET_SIZING_METHOD_NAME);
|
|
23291
|
+
return backtest$1.sizingSchemaService.get(sizingName);
|
|
23292
|
+
}
|
|
23293
|
+
/**
|
|
23294
|
+
* Retrieves a registered risk schema by name.
|
|
23295
|
+
*
|
|
23296
|
+
* @param riskName - Unique risk identifier
|
|
23297
|
+
* @returns The risk schema configuration object
|
|
23298
|
+
* @throws Error if risk is not registered
|
|
23299
|
+
*
|
|
23300
|
+
* @example
|
|
23301
|
+
* ```typescript
|
|
23302
|
+
* const risk = getRisk("conservative");
|
|
23303
|
+
* console.log(risk.maxConcurrentPositions); // 5
|
|
23304
|
+
* console.log(risk.validations); // Array of validation functions
|
|
23305
|
+
* ```
|
|
23306
|
+
*/
|
|
23307
|
+
function getRiskSchema(riskName) {
|
|
23308
|
+
backtest$1.loggerService.log(GET_RISK_METHOD_NAME, {
|
|
23309
|
+
riskName,
|
|
23310
|
+
});
|
|
23311
|
+
backtest$1.riskValidationService.validate(riskName, GET_RISK_METHOD_NAME);
|
|
23312
|
+
return backtest$1.riskSchemaService.get(riskName);
|
|
23313
|
+
}
|
|
23314
|
+
/**
|
|
23315
|
+
* Retrieves a registered optimizer schema by name.
|
|
23316
|
+
*
|
|
23317
|
+
* @param optimizerName - Unique optimizer identifier
|
|
23318
|
+
* @returns The optimizer schema configuration object
|
|
23319
|
+
* @throws Error if optimizer is not registered
|
|
23320
|
+
*
|
|
23321
|
+
* @example
|
|
23322
|
+
* ```typescript
|
|
23323
|
+
* const optimizer = getOptimizer("llm-strategy-generator");
|
|
23324
|
+
* console.log(optimizer.rangeTrain); // Array of training ranges
|
|
23325
|
+
* console.log(optimizer.rangeTest); // Testing range
|
|
23326
|
+
* console.log(optimizer.source); // Array of data sources
|
|
23327
|
+
* console.log(optimizer.getPrompt); // async function
|
|
23328
|
+
* ```
|
|
23329
|
+
*/
|
|
23330
|
+
function getOptimizerSchema(optimizerName) {
|
|
23331
|
+
backtest$1.loggerService.log(GET_OPTIMIZER_METHOD_NAME, {
|
|
23332
|
+
optimizerName,
|
|
23333
|
+
});
|
|
23334
|
+
backtest$1.optimizerValidationService.validate(optimizerName, GET_OPTIMIZER_METHOD_NAME);
|
|
23335
|
+
return backtest$1.optimizerSchemaService.get(optimizerName);
|
|
23336
|
+
}
|
|
23337
|
+
/**
|
|
23338
|
+
* Retrieves a registered action schema by name.
|
|
23339
|
+
*
|
|
23340
|
+
* @param actionName - Unique action identifier
|
|
23341
|
+
* @returns The action schema configuration object
|
|
23342
|
+
* @throws Error if action is not registered
|
|
23343
|
+
*
|
|
23344
|
+
* @example
|
|
23345
|
+
* ```typescript
|
|
23346
|
+
* const action = getAction("telegram-notifier");
|
|
23347
|
+
* console.log(action.handler); // Class constructor or object
|
|
23348
|
+
* console.log(action.callbacks); // Optional lifecycle callbacks
|
|
23349
|
+
* ```
|
|
23350
|
+
*/
|
|
23351
|
+
function getActionSchema(actionName) {
|
|
23352
|
+
backtest$1.loggerService.log(GET_ACTION_METHOD_NAME, {
|
|
23353
|
+
actionName,
|
|
23354
|
+
});
|
|
23355
|
+
backtest$1.actionValidationService.validate(actionName, GET_ACTION_METHOD_NAME);
|
|
23356
|
+
return backtest$1.actionSchemaService.get(actionName);
|
|
23357
|
+
}
|
|
23358
|
+
|
|
22829
23359
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
22830
23360
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
22831
23361
|
const FORMAT_PRICE_METHOD_NAME = "exchange.formatPrice";
|
|
22832
23362
|
const FORMAT_QUANTITY_METHOD_NAME = "exchange.formatQuantity";
|
|
22833
23363
|
const GET_DATE_METHOD_NAME = "exchange.getDate";
|
|
22834
23364
|
const GET_MODE_METHOD_NAME = "exchange.getMode";
|
|
23365
|
+
const GET_SYMBOL_METHOD_NAME = "exchange.getSymbol";
|
|
23366
|
+
const GET_CONTEXT_METHOD_NAME = "exchange.getContext";
|
|
22835
23367
|
const HAS_TRADE_CONTEXT_METHOD_NAME = "exchange.hasTradeContext";
|
|
22836
23368
|
const GET_ORDER_BOOK_METHOD_NAME = "exchange.getOrderBook";
|
|
22837
23369
|
/**
|
|
@@ -23014,6 +23546,48 @@ async function getMode() {
|
|
|
23014
23546
|
const { backtest: bt } = backtest$1.executionContextService.context;
|
|
23015
23547
|
return bt ? "backtest" : "live";
|
|
23016
23548
|
}
|
|
23549
|
+
/**
|
|
23550
|
+
* Gets the current trading symbol from execution context.
|
|
23551
|
+
*
|
|
23552
|
+
* @returns Promise resolving to the current trading symbol (e.g., "BTCUSDT")
|
|
23553
|
+
* @throws Error if execution context is not active
|
|
23554
|
+
*
|
|
23555
|
+
* @example
|
|
23556
|
+
* ```typescript
|
|
23557
|
+
* const symbol = await getSymbol();
|
|
23558
|
+
* console.log(symbol); // "BTCUSDT"
|
|
23559
|
+
* ```
|
|
23560
|
+
*/
|
|
23561
|
+
async function getSymbol() {
|
|
23562
|
+
backtest$1.loggerService.info(GET_SYMBOL_METHOD_NAME);
|
|
23563
|
+
if (!ExecutionContextService.hasContext()) {
|
|
23564
|
+
throw new Error("getSymbol requires an execution context");
|
|
23565
|
+
}
|
|
23566
|
+
const { symbol } = backtest$1.executionContextService.context;
|
|
23567
|
+
return symbol;
|
|
23568
|
+
}
|
|
23569
|
+
/**
|
|
23570
|
+
* Gets the current method context.
|
|
23571
|
+
*
|
|
23572
|
+
* Returns the context object from the method context service, which contains
|
|
23573
|
+
* information about the current method execution environment.
|
|
23574
|
+
*
|
|
23575
|
+
* @returns Promise resolving to the current method context object
|
|
23576
|
+
* @throws Error if method context is not active
|
|
23577
|
+
*
|
|
23578
|
+
* @example
|
|
23579
|
+
* ```typescript
|
|
23580
|
+
* const context = await getContext();
|
|
23581
|
+
* console.log(context); // { ...method context data... }
|
|
23582
|
+
* ```
|
|
23583
|
+
*/
|
|
23584
|
+
async function getContext() {
|
|
23585
|
+
backtest$1.loggerService.info(GET_CONTEXT_METHOD_NAME);
|
|
23586
|
+
if (!MethodContextService.hasContext()) {
|
|
23587
|
+
throw new Error("getContext requires a method context");
|
|
23588
|
+
}
|
|
23589
|
+
return backtest$1.methodContextService.context;
|
|
23590
|
+
}
|
|
23017
23591
|
/**
|
|
23018
23592
|
* Fetches order book for a trading pair from the registered exchange.
|
|
23019
23593
|
*
|
|
@@ -23050,52 +23624,12 @@ async function getOrderBook(symbol, depth) {
|
|
|
23050
23624
|
return await backtest$1.exchangeConnectionService.getOrderBook(symbol, depth);
|
|
23051
23625
|
}
|
|
23052
23626
|
|
|
23053
|
-
const
|
|
23054
|
-
const
|
|
23055
|
-
const
|
|
23056
|
-
const
|
|
23057
|
-
const
|
|
23058
|
-
const
|
|
23059
|
-
const BREAKEVEN_METHOD_NAME = "strategy.breakeven";
|
|
23060
|
-
/**
|
|
23061
|
-
* Stops the strategy from generating new signals.
|
|
23062
|
-
*
|
|
23063
|
-
* Sets internal flag to prevent strategy from opening new signals.
|
|
23064
|
-
* Current active signal (if any) will complete normally.
|
|
23065
|
-
* Backtest/Live mode will stop at the next safe point (idle state or after signal closes).
|
|
23066
|
-
*
|
|
23067
|
-
* Automatically detects backtest/live mode from execution context.
|
|
23068
|
-
*
|
|
23069
|
-
* @param symbol - Trading pair symbol
|
|
23070
|
-
* @param strategyName - Strategy name to stop
|
|
23071
|
-
* @returns Promise that resolves when stop flag is set
|
|
23072
|
-
*
|
|
23073
|
-
* @example
|
|
23074
|
-
* ```typescript
|
|
23075
|
-
* import { stop } from "backtest-kit";
|
|
23076
|
-
*
|
|
23077
|
-
* // Stop strategy after some condition
|
|
23078
|
-
* await stop("BTCUSDT", "my-strategy");
|
|
23079
|
-
* ```
|
|
23080
|
-
*/
|
|
23081
|
-
async function stop(symbol) {
|
|
23082
|
-
backtest$1.loggerService.info(STOP_METHOD_NAME, {
|
|
23083
|
-
symbol,
|
|
23084
|
-
});
|
|
23085
|
-
if (!ExecutionContextService.hasContext()) {
|
|
23086
|
-
throw new Error("stop requires an execution context");
|
|
23087
|
-
}
|
|
23088
|
-
if (!MethodContextService.hasContext()) {
|
|
23089
|
-
throw new Error("stop requires a method context");
|
|
23090
|
-
}
|
|
23091
|
-
const { backtest: isBacktest } = backtest$1.executionContextService.context;
|
|
23092
|
-
const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
|
|
23093
|
-
await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
|
|
23094
|
-
exchangeName,
|
|
23095
|
-
frameName,
|
|
23096
|
-
strategyName,
|
|
23097
|
-
});
|
|
23098
|
-
}
|
|
23627
|
+
const CANCEL_METHOD_NAME = "strategy.commitCancel";
|
|
23628
|
+
const PARTIAL_PROFIT_METHOD_NAME = "strategy.commitPartialProfit";
|
|
23629
|
+
const PARTIAL_LOSS_METHOD_NAME = "strategy.commitPartialLoss";
|
|
23630
|
+
const TRAILING_STOP_METHOD_NAME = "strategy.commitTrailingStop";
|
|
23631
|
+
const TRAILING_PROFIT_METHOD_NAME = "strategy.commitTrailingTake";
|
|
23632
|
+
const BREAKEVEN_METHOD_NAME = "strategy.commitBreakeven";
|
|
23099
23633
|
/**
|
|
23100
23634
|
* Cancels the scheduled signal without stopping the strategy.
|
|
23101
23635
|
*
|
|
@@ -23118,7 +23652,7 @@ async function stop(symbol) {
|
|
|
23118
23652
|
* await cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
23119
23653
|
* ```
|
|
23120
23654
|
*/
|
|
23121
|
-
async function
|
|
23655
|
+
async function commitCancel(symbol, cancelId) {
|
|
23122
23656
|
backtest$1.loggerService.info(CANCEL_METHOD_NAME, {
|
|
23123
23657
|
symbol,
|
|
23124
23658
|
cancelId,
|
|
@@ -23160,7 +23694,7 @@ async function cancel(symbol, cancelId) {
|
|
|
23160
23694
|
* }
|
|
23161
23695
|
* ```
|
|
23162
23696
|
*/
|
|
23163
|
-
async function
|
|
23697
|
+
async function commitPartialProfit(symbol, percentToClose) {
|
|
23164
23698
|
backtest$1.loggerService.info(PARTIAL_PROFIT_METHOD_NAME, {
|
|
23165
23699
|
symbol,
|
|
23166
23700
|
percentToClose,
|
|
@@ -23203,7 +23737,7 @@ async function partialProfit(symbol, percentToClose) {
|
|
|
23203
23737
|
* }
|
|
23204
23738
|
* ```
|
|
23205
23739
|
*/
|
|
23206
|
-
async function
|
|
23740
|
+
async function commitPartialLoss(symbol, percentToClose) {
|
|
23207
23741
|
backtest$1.loggerService.info(PARTIAL_LOSS_METHOD_NAME, {
|
|
23208
23742
|
symbol,
|
|
23209
23743
|
percentToClose,
|
|
@@ -23262,7 +23796,7 @@ async function partialLoss(symbol, percentToClose) {
|
|
|
23262
23796
|
* // success3 = true (ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95, better protection)
|
|
23263
23797
|
* ```
|
|
23264
23798
|
*/
|
|
23265
|
-
async function
|
|
23799
|
+
async function commitTrailingStop(symbol, percentShift, currentPrice) {
|
|
23266
23800
|
backtest$1.loggerService.info(TRAILING_STOP_METHOD_NAME, {
|
|
23267
23801
|
symbol,
|
|
23268
23802
|
percentShift,
|
|
@@ -23321,7 +23855,7 @@ async function trailingStop(symbol, percentShift, currentPrice) {
|
|
|
23321
23855
|
* // success3 = true (ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107, more conservative)
|
|
23322
23856
|
* ```
|
|
23323
23857
|
*/
|
|
23324
|
-
async function
|
|
23858
|
+
async function commitTrailingTake(symbol, percentShift, currentPrice) {
|
|
23325
23859
|
backtest$1.loggerService.info(TRAILING_PROFIT_METHOD_NAME, {
|
|
23326
23860
|
symbol,
|
|
23327
23861
|
percentShift,
|
|
@@ -23362,7 +23896,7 @@ async function trailingTake(symbol, percentShift, currentPrice) {
|
|
|
23362
23896
|
* }
|
|
23363
23897
|
* ```
|
|
23364
23898
|
*/
|
|
23365
|
-
async function
|
|
23899
|
+
async function commitBreakeven(symbol) {
|
|
23366
23900
|
backtest$1.loggerService.info(BREAKEVEN_METHOD_NAME, {
|
|
23367
23901
|
symbol,
|
|
23368
23902
|
});
|
|
@@ -23378,6 +23912,47 @@ async function breakeven(symbol) {
|
|
|
23378
23912
|
return await backtest$1.strategyCoreService.breakeven(isBacktest, symbol, currentPrice, { exchangeName, frameName, strategyName });
|
|
23379
23913
|
}
|
|
23380
23914
|
|
|
23915
|
+
const STOP_METHOD_NAME = "control.stop";
|
|
23916
|
+
/**
|
|
23917
|
+
* Stops the strategy from generating new signals.
|
|
23918
|
+
*
|
|
23919
|
+
* Sets internal flag to prevent strategy from opening new signals.
|
|
23920
|
+
* Current active signal (if any) will complete normally.
|
|
23921
|
+
* Backtest/Live mode will stop at the next safe point (idle state or after signal closes).
|
|
23922
|
+
*
|
|
23923
|
+
* Automatically detects backtest/live mode from execution context.
|
|
23924
|
+
*
|
|
23925
|
+
* @param symbol - Trading pair symbol
|
|
23926
|
+
* @param strategyName - Strategy name to stop
|
|
23927
|
+
* @returns Promise that resolves when stop flag is set
|
|
23928
|
+
*
|
|
23929
|
+
* @example
|
|
23930
|
+
* ```typescript
|
|
23931
|
+
* import { stop } from "backtest-kit";
|
|
23932
|
+
*
|
|
23933
|
+
* // Stop strategy after some condition
|
|
23934
|
+
* await stop("BTCUSDT", "my-strategy");
|
|
23935
|
+
* ```
|
|
23936
|
+
*/
|
|
23937
|
+
async function stop(symbol) {
|
|
23938
|
+
backtest$1.loggerService.info(STOP_METHOD_NAME, {
|
|
23939
|
+
symbol,
|
|
23940
|
+
});
|
|
23941
|
+
if (!ExecutionContextService.hasContext()) {
|
|
23942
|
+
throw new Error("stop requires an execution context");
|
|
23943
|
+
}
|
|
23944
|
+
if (!MethodContextService.hasContext()) {
|
|
23945
|
+
throw new Error("stop requires a method context");
|
|
23946
|
+
}
|
|
23947
|
+
const { backtest: isBacktest } = backtest$1.executionContextService.context;
|
|
23948
|
+
const { exchangeName, frameName, strategyName } = backtest$1.methodContextService.context;
|
|
23949
|
+
await backtest$1.strategyCoreService.stop(isBacktest, symbol, {
|
|
23950
|
+
exchangeName,
|
|
23951
|
+
frameName,
|
|
23952
|
+
strategyName,
|
|
23953
|
+
});
|
|
23954
|
+
}
|
|
23955
|
+
|
|
23381
23956
|
/**
|
|
23382
23957
|
* Sets custom logger implementation for the framework.
|
|
23383
23958
|
*
|
|
@@ -23528,14 +24103,14 @@ function getDefaultColumns() {
|
|
|
23528
24103
|
return DEFAULT_COLUMNS;
|
|
23529
24104
|
}
|
|
23530
24105
|
|
|
23531
|
-
const ADD_STRATEGY_METHOD_NAME = "add.
|
|
23532
|
-
const ADD_EXCHANGE_METHOD_NAME = "add.
|
|
23533
|
-
const ADD_FRAME_METHOD_NAME = "add.
|
|
23534
|
-
const ADD_WALKER_METHOD_NAME = "add.
|
|
23535
|
-
const ADD_SIZING_METHOD_NAME = "add.
|
|
23536
|
-
const ADD_RISK_METHOD_NAME = "add.
|
|
23537
|
-
const ADD_OPTIMIZER_METHOD_NAME = "add.
|
|
23538
|
-
const ADD_ACTION_METHOD_NAME = "add.
|
|
24106
|
+
const ADD_STRATEGY_METHOD_NAME = "add.addStrategySchema";
|
|
24107
|
+
const ADD_EXCHANGE_METHOD_NAME = "add.addExchangeSchema";
|
|
24108
|
+
const ADD_FRAME_METHOD_NAME = "add.addFrameSchema";
|
|
24109
|
+
const ADD_WALKER_METHOD_NAME = "add.addWalkerSchema";
|
|
24110
|
+
const ADD_SIZING_METHOD_NAME = "add.addSizingSchema";
|
|
24111
|
+
const ADD_RISK_METHOD_NAME = "add.addRiskSchema";
|
|
24112
|
+
const ADD_OPTIMIZER_METHOD_NAME = "add.addOptimizerSchema";
|
|
24113
|
+
const ADD_ACTION_METHOD_NAME = "add.addActionSchema";
|
|
23539
24114
|
/**
|
|
23540
24115
|
* Registers a trading strategy in the framework.
|
|
23541
24116
|
*
|
|
@@ -23570,7 +24145,7 @@ const ADD_ACTION_METHOD_NAME = "add.addAction";
|
|
|
23570
24145
|
* });
|
|
23571
24146
|
* ```
|
|
23572
24147
|
*/
|
|
23573
|
-
function
|
|
24148
|
+
function addStrategySchema(strategySchema) {
|
|
23574
24149
|
backtest$1.loggerService.info(ADD_STRATEGY_METHOD_NAME, {
|
|
23575
24150
|
strategySchema,
|
|
23576
24151
|
});
|
|
@@ -23612,7 +24187,7 @@ function addStrategy(strategySchema) {
|
|
|
23612
24187
|
* });
|
|
23613
24188
|
* ```
|
|
23614
24189
|
*/
|
|
23615
|
-
function
|
|
24190
|
+
function addExchangeSchema(exchangeSchema) {
|
|
23616
24191
|
backtest$1.loggerService.info(ADD_EXCHANGE_METHOD_NAME, {
|
|
23617
24192
|
exchangeSchema,
|
|
23618
24193
|
});
|
|
@@ -23649,7 +24224,7 @@ function addExchange(exchangeSchema) {
|
|
|
23649
24224
|
* });
|
|
23650
24225
|
* ```
|
|
23651
24226
|
*/
|
|
23652
|
-
function
|
|
24227
|
+
function addFrameSchema(frameSchema) {
|
|
23653
24228
|
backtest$1.loggerService.info(ADD_FRAME_METHOD_NAME, {
|
|
23654
24229
|
frameSchema,
|
|
23655
24230
|
});
|
|
@@ -23693,7 +24268,7 @@ function addFrame(frameSchema) {
|
|
|
23693
24268
|
* });
|
|
23694
24269
|
* ```
|
|
23695
24270
|
*/
|
|
23696
|
-
function
|
|
24271
|
+
function addWalkerSchema(walkerSchema) {
|
|
23697
24272
|
backtest$1.loggerService.info(ADD_WALKER_METHOD_NAME, {
|
|
23698
24273
|
walkerSchema,
|
|
23699
24274
|
});
|
|
@@ -23752,7 +24327,7 @@ function addWalker(walkerSchema) {
|
|
|
23752
24327
|
* });
|
|
23753
24328
|
* ```
|
|
23754
24329
|
*/
|
|
23755
|
-
function
|
|
24330
|
+
function addSizingSchema(sizingSchema) {
|
|
23756
24331
|
backtest$1.loggerService.info(ADD_SIZING_METHOD_NAME, {
|
|
23757
24332
|
sizingSchema,
|
|
23758
24333
|
});
|
|
@@ -23820,7 +24395,7 @@ function addSizing(sizingSchema) {
|
|
|
23820
24395
|
* });
|
|
23821
24396
|
* ```
|
|
23822
24397
|
*/
|
|
23823
|
-
function
|
|
24398
|
+
function addRiskSchema(riskSchema) {
|
|
23824
24399
|
backtest$1.loggerService.info(ADD_RISK_METHOD_NAME, {
|
|
23825
24400
|
riskSchema,
|
|
23826
24401
|
});
|
|
@@ -23914,7 +24489,7 @@ function addRisk(riskSchema) {
|
|
|
23914
24489
|
* });
|
|
23915
24490
|
* ```
|
|
23916
24491
|
*/
|
|
23917
|
-
function
|
|
24492
|
+
function addOptimizerSchema(optimizerSchema) {
|
|
23918
24493
|
backtest$1.loggerService.info(ADD_OPTIMIZER_METHOD_NAME, {
|
|
23919
24494
|
optimizerSchema,
|
|
23920
24495
|
});
|
|
@@ -23989,7 +24564,7 @@ function addOptimizer(optimizerSchema) {
|
|
|
23989
24564
|
* });
|
|
23990
24565
|
* ```
|
|
23991
24566
|
*/
|
|
23992
|
-
function
|
|
24567
|
+
function addActionSchema(actionSchema) {
|
|
23993
24568
|
backtest$1.loggerService.info(ADD_ACTION_METHOD_NAME, {
|
|
23994
24569
|
actionSchema,
|
|
23995
24570
|
});
|
|
@@ -23997,14 +24572,14 @@ function addAction(actionSchema) {
|
|
|
23997
24572
|
backtest$1.actionSchemaService.register(actionSchema.actionName, actionSchema);
|
|
23998
24573
|
}
|
|
23999
24574
|
|
|
24000
|
-
const METHOD_NAME_OVERRIDE_STRATEGY = "function.override.
|
|
24001
|
-
const METHOD_NAME_OVERRIDE_EXCHANGE = "function.override.
|
|
24002
|
-
const METHOD_NAME_OVERRIDE_FRAME = "function.override.
|
|
24003
|
-
const METHOD_NAME_OVERRIDE_WALKER = "function.override.
|
|
24004
|
-
const METHOD_NAME_OVERRIDE_SIZING = "function.override.
|
|
24005
|
-
const METHOD_NAME_OVERRIDE_RISK = "function.override.
|
|
24006
|
-
const METHOD_NAME_OVERRIDE_OPTIMIZER = "function.override.
|
|
24007
|
-
const METHOD_NAME_OVERRIDE_ACTION = "function.override.
|
|
24575
|
+
const METHOD_NAME_OVERRIDE_STRATEGY = "function.override.overrideStrategySchema";
|
|
24576
|
+
const METHOD_NAME_OVERRIDE_EXCHANGE = "function.override.overrideExchangeSchema";
|
|
24577
|
+
const METHOD_NAME_OVERRIDE_FRAME = "function.override.overrideFrameSchema";
|
|
24578
|
+
const METHOD_NAME_OVERRIDE_WALKER = "function.override.overrideWalkerSchema";
|
|
24579
|
+
const METHOD_NAME_OVERRIDE_SIZING = "function.override.overrideSizingSchema";
|
|
24580
|
+
const METHOD_NAME_OVERRIDE_RISK = "function.override.overrideRiskSchema";
|
|
24581
|
+
const METHOD_NAME_OVERRIDE_OPTIMIZER = "function.override.overrideOptimizerSchema";
|
|
24582
|
+
const METHOD_NAME_OVERRIDE_ACTION = "function.override.overrideActionSchema";
|
|
24008
24583
|
/**
|
|
24009
24584
|
* Overrides an existing trading strategy in the framework.
|
|
24010
24585
|
*
|
|
@@ -24025,7 +24600,7 @@ const METHOD_NAME_OVERRIDE_ACTION = "function.override.overrideAction";
|
|
|
24025
24600
|
* });
|
|
24026
24601
|
* ```
|
|
24027
24602
|
*/
|
|
24028
|
-
async function
|
|
24603
|
+
async function overrideStrategySchema(strategySchema) {
|
|
24029
24604
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_STRATEGY, {
|
|
24030
24605
|
strategySchema,
|
|
24031
24606
|
});
|
|
@@ -24053,7 +24628,7 @@ async function overrideStrategy(strategySchema) {
|
|
|
24053
24628
|
* });
|
|
24054
24629
|
* ```
|
|
24055
24630
|
*/
|
|
24056
|
-
async function
|
|
24631
|
+
async function overrideExchangeSchema(exchangeSchema) {
|
|
24057
24632
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_EXCHANGE, {
|
|
24058
24633
|
exchangeSchema,
|
|
24059
24634
|
});
|
|
@@ -24081,7 +24656,7 @@ async function overrideExchange(exchangeSchema) {
|
|
|
24081
24656
|
* });
|
|
24082
24657
|
* ```
|
|
24083
24658
|
*/
|
|
24084
|
-
async function
|
|
24659
|
+
async function overrideFrameSchema(frameSchema) {
|
|
24085
24660
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_FRAME, {
|
|
24086
24661
|
frameSchema,
|
|
24087
24662
|
});
|
|
@@ -24110,7 +24685,7 @@ async function overrideFrame(frameSchema) {
|
|
|
24110
24685
|
* });
|
|
24111
24686
|
* ```
|
|
24112
24687
|
*/
|
|
24113
|
-
async function
|
|
24688
|
+
async function overrideWalkerSchema(walkerSchema) {
|
|
24114
24689
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_WALKER, {
|
|
24115
24690
|
walkerSchema,
|
|
24116
24691
|
});
|
|
@@ -24142,7 +24717,7 @@ async function overrideWalker(walkerSchema) {
|
|
|
24142
24717
|
* });
|
|
24143
24718
|
* ```
|
|
24144
24719
|
*/
|
|
24145
|
-
async function
|
|
24720
|
+
async function overrideSizingSchema(sizingSchema) {
|
|
24146
24721
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_SIZING, {
|
|
24147
24722
|
sizingSchema,
|
|
24148
24723
|
});
|
|
@@ -24169,7 +24744,7 @@ async function overrideSizing(sizingSchema) {
|
|
|
24169
24744
|
* });
|
|
24170
24745
|
* ```
|
|
24171
24746
|
*/
|
|
24172
|
-
async function
|
|
24747
|
+
async function overrideRiskSchema(riskSchema) {
|
|
24173
24748
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_RISK, {
|
|
24174
24749
|
riskSchema,
|
|
24175
24750
|
});
|
|
@@ -24203,7 +24778,7 @@ async function overrideRisk(riskSchema) {
|
|
|
24203
24778
|
* });
|
|
24204
24779
|
* ```
|
|
24205
24780
|
*/
|
|
24206
|
-
async function
|
|
24781
|
+
async function overrideOptimizerSchema(optimizerSchema) {
|
|
24207
24782
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_OPTIMIZER, {
|
|
24208
24783
|
optimizerSchema,
|
|
24209
24784
|
});
|
|
@@ -24270,7 +24845,7 @@ async function overrideOptimizer(optimizerSchema) {
|
|
|
24270
24845
|
* });
|
|
24271
24846
|
* ```
|
|
24272
24847
|
*/
|
|
24273
|
-
async function
|
|
24848
|
+
async function overrideActionSchema(actionSchema) {
|
|
24274
24849
|
backtest$1.loggerService.log(METHOD_NAME_OVERRIDE_ACTION, {
|
|
24275
24850
|
actionSchema,
|
|
24276
24851
|
});
|
|
@@ -24278,13 +24853,13 @@ async function overrideAction(actionSchema) {
|
|
|
24278
24853
|
return backtest$1.actionSchemaService.override(actionSchema.actionName, actionSchema);
|
|
24279
24854
|
}
|
|
24280
24855
|
|
|
24281
|
-
const LIST_EXCHANGES_METHOD_NAME = "list.
|
|
24282
|
-
const LIST_STRATEGIES_METHOD_NAME = "list.
|
|
24283
|
-
const LIST_FRAMES_METHOD_NAME = "list.
|
|
24284
|
-
const LIST_WALKERS_METHOD_NAME = "list.
|
|
24285
|
-
const LIST_SIZINGS_METHOD_NAME = "list.
|
|
24286
|
-
const LIST_RISKS_METHOD_NAME = "list.
|
|
24287
|
-
const LIST_OPTIMIZERS_METHOD_NAME = "list.
|
|
24856
|
+
const LIST_EXCHANGES_METHOD_NAME = "list.listExchangeSchema";
|
|
24857
|
+
const LIST_STRATEGIES_METHOD_NAME = "list.listStrategySchema";
|
|
24858
|
+
const LIST_FRAMES_METHOD_NAME = "list.listFrameSchema";
|
|
24859
|
+
const LIST_WALKERS_METHOD_NAME = "list.listWalkerSchema";
|
|
24860
|
+
const LIST_SIZINGS_METHOD_NAME = "list.listSizingSchema";
|
|
24861
|
+
const LIST_RISKS_METHOD_NAME = "list.listRiskSchema";
|
|
24862
|
+
const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizerSchema";
|
|
24288
24863
|
/**
|
|
24289
24864
|
* Returns a list of all registered exchange schemas.
|
|
24290
24865
|
*
|
|
@@ -24310,7 +24885,7 @@ const LIST_OPTIMIZERS_METHOD_NAME = "list.listOptimizers";
|
|
|
24310
24885
|
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
24311
24886
|
* ```
|
|
24312
24887
|
*/
|
|
24313
|
-
async function
|
|
24888
|
+
async function listExchangeSchema() {
|
|
24314
24889
|
backtest$1.loggerService.log(LIST_EXCHANGES_METHOD_NAME);
|
|
24315
24890
|
return await backtest$1.exchangeValidationService.list();
|
|
24316
24891
|
}
|
|
@@ -24344,7 +24919,7 @@ async function listExchanges() {
|
|
|
24344
24919
|
* // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
|
|
24345
24920
|
* ```
|
|
24346
24921
|
*/
|
|
24347
|
-
async function
|
|
24922
|
+
async function listStrategySchema() {
|
|
24348
24923
|
backtest$1.loggerService.log(LIST_STRATEGIES_METHOD_NAME);
|
|
24349
24924
|
return await backtest$1.strategyValidationService.list();
|
|
24350
24925
|
}
|
|
@@ -24373,7 +24948,7 @@ async function listStrategies() {
|
|
|
24373
24948
|
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
24374
24949
|
* ```
|
|
24375
24950
|
*/
|
|
24376
|
-
async function
|
|
24951
|
+
async function listFrameSchema() {
|
|
24377
24952
|
backtest$1.loggerService.log(LIST_FRAMES_METHOD_NAME);
|
|
24378
24953
|
return await backtest$1.frameValidationService.list();
|
|
24379
24954
|
}
|
|
@@ -24403,7 +24978,7 @@ async function listFrames() {
|
|
|
24403
24978
|
* // [{ walkerName: "llm-prompt-optimizer", note: "Compare LLM...", ... }]
|
|
24404
24979
|
* ```
|
|
24405
24980
|
*/
|
|
24406
|
-
async function
|
|
24981
|
+
async function listWalkerSchema() {
|
|
24407
24982
|
backtest$1.loggerService.log(LIST_WALKERS_METHOD_NAME);
|
|
24408
24983
|
return await backtest$1.walkerValidationService.list();
|
|
24409
24984
|
}
|
|
@@ -24442,7 +25017,7 @@ async function listWalkers() {
|
|
|
24442
25017
|
* // ]
|
|
24443
25018
|
* ```
|
|
24444
25019
|
*/
|
|
24445
|
-
async function
|
|
25020
|
+
async function listSizingSchema() {
|
|
24446
25021
|
backtest$1.loggerService.log(LIST_SIZINGS_METHOD_NAME);
|
|
24447
25022
|
return await backtest$1.sizingValidationService.list();
|
|
24448
25023
|
}
|
|
@@ -24478,7 +25053,7 @@ async function listSizings() {
|
|
|
24478
25053
|
* // ]
|
|
24479
25054
|
* ```
|
|
24480
25055
|
*/
|
|
24481
|
-
async function
|
|
25056
|
+
async function listRiskSchema() {
|
|
24482
25057
|
backtest$1.loggerService.log(LIST_RISKS_METHOD_NAME);
|
|
24483
25058
|
return await backtest$1.riskValidationService.list();
|
|
24484
25059
|
}
|
|
@@ -24518,7 +25093,7 @@ async function listRisks() {
|
|
|
24518
25093
|
* // [{ optimizerName: "llm-strategy-generator", note: "Generates...", ... }]
|
|
24519
25094
|
* ```
|
|
24520
25095
|
*/
|
|
24521
|
-
async function
|
|
25096
|
+
async function listOptimizerSchema() {
|
|
24522
25097
|
backtest$1.loggerService.log(LIST_OPTIMIZERS_METHOD_NAME);
|
|
24523
25098
|
return await backtest$1.optimizerValidationService.list();
|
|
24524
25099
|
}
|
|
@@ -24553,8 +25128,10 @@ const LISTEN_BREAKEVEN_METHOD_NAME = "event.listenBreakeven";
|
|
|
24553
25128
|
const LISTEN_BREAKEVEN_ONCE_METHOD_NAME = "event.listenBreakevenOnce";
|
|
24554
25129
|
const LISTEN_RISK_METHOD_NAME = "event.listenRisk";
|
|
24555
25130
|
const LISTEN_RISK_ONCE_METHOD_NAME = "event.listenRiskOnce";
|
|
24556
|
-
const
|
|
24557
|
-
const
|
|
25131
|
+
const LISTEN_SCHEDULE_PING_METHOD_NAME = "event.listenSchedulePing";
|
|
25132
|
+
const LISTEN_SCHEDULE_PING_ONCE_METHOD_NAME = "event.listenSchedulePingOnce";
|
|
25133
|
+
const LISTEN_ACTIVE_PING_METHOD_NAME = "event.listenActivePing";
|
|
25134
|
+
const LISTEN_ACTIVE_PING_ONCE_METHOD_NAME = "event.listenActivePingOnce";
|
|
24558
25135
|
/**
|
|
24559
25136
|
* Subscribes to all signal events with queued async processing.
|
|
24560
25137
|
*
|
|
@@ -25253,7 +25830,7 @@ function listenValidation(fn) {
|
|
|
25253
25830
|
* unsubscribe();
|
|
25254
25831
|
* ```
|
|
25255
25832
|
*/
|
|
25256
|
-
function
|
|
25833
|
+
function listenPartialProfitAvailable(fn) {
|
|
25257
25834
|
backtest$1.loggerService.log(LISTEN_PARTIAL_PROFIT_METHOD_NAME);
|
|
25258
25835
|
return partialProfitSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
25259
25836
|
}
|
|
@@ -25287,7 +25864,7 @@ function listenPartialProfit(fn) {
|
|
|
25287
25864
|
* cancel();
|
|
25288
25865
|
* ```
|
|
25289
25866
|
*/
|
|
25290
|
-
function
|
|
25867
|
+
function listenPartialProfitAvailableOnce(filterFn, fn) {
|
|
25291
25868
|
backtest$1.loggerService.log(LISTEN_PARTIAL_PROFIT_ONCE_METHOD_NAME);
|
|
25292
25869
|
return partialProfitSubject.filter(filterFn).once(fn);
|
|
25293
25870
|
}
|
|
@@ -25315,7 +25892,7 @@ function listenPartialProfitOnce(filterFn, fn) {
|
|
|
25315
25892
|
* unsubscribe();
|
|
25316
25893
|
* ```
|
|
25317
25894
|
*/
|
|
25318
|
-
function
|
|
25895
|
+
function listenPartialLossAvailable(fn) {
|
|
25319
25896
|
backtest$1.loggerService.log(LISTEN_PARTIAL_LOSS_METHOD_NAME);
|
|
25320
25897
|
return partialLossSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
25321
25898
|
}
|
|
@@ -25349,7 +25926,7 @@ function listenPartialLoss(fn) {
|
|
|
25349
25926
|
* cancel();
|
|
25350
25927
|
* ```
|
|
25351
25928
|
*/
|
|
25352
|
-
function
|
|
25929
|
+
function listenPartialLossAvailableOnce(filterFn, fn) {
|
|
25353
25930
|
backtest$1.loggerService.log(LISTEN_PARTIAL_LOSS_ONCE_METHOD_NAME);
|
|
25354
25931
|
return partialLossSubject.filter(filterFn).once(fn);
|
|
25355
25932
|
}
|
|
@@ -25379,7 +25956,7 @@ function listenPartialLossOnce(filterFn, fn) {
|
|
|
25379
25956
|
* unsubscribe();
|
|
25380
25957
|
* ```
|
|
25381
25958
|
*/
|
|
25382
|
-
function
|
|
25959
|
+
function listenBreakevenAvailable(fn) {
|
|
25383
25960
|
backtest$1.loggerService.log(LISTEN_BREAKEVEN_METHOD_NAME);
|
|
25384
25961
|
return breakevenSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
25385
25962
|
}
|
|
@@ -25413,7 +25990,7 @@ function listenBreakeven(fn) {
|
|
|
25413
25990
|
* cancel();
|
|
25414
25991
|
* ```
|
|
25415
25992
|
*/
|
|
25416
|
-
function
|
|
25993
|
+
function listenBreakevenAvailableOnce(filterFn, fn) {
|
|
25417
25994
|
backtest$1.loggerService.log(LISTEN_BREAKEVEN_ONCE_METHOD_NAME);
|
|
25418
25995
|
return breakevenSubject.filter(filterFn).once(fn);
|
|
25419
25996
|
}
|
|
@@ -25509,9 +26086,9 @@ function listenRiskOnce(filterFn, fn) {
|
|
|
25509
26086
|
* unsubscribe();
|
|
25510
26087
|
* ```
|
|
25511
26088
|
*/
|
|
25512
|
-
function
|
|
25513
|
-
backtest$1.loggerService.log(
|
|
25514
|
-
return
|
|
26089
|
+
function listenSchedulePing(fn) {
|
|
26090
|
+
backtest$1.loggerService.log(LISTEN_SCHEDULE_PING_METHOD_NAME);
|
|
26091
|
+
return schedulePingSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
25515
26092
|
}
|
|
25516
26093
|
/**
|
|
25517
26094
|
* Subscribes to filtered ping events with one-time execution.
|
|
@@ -25543,9 +26120,74 @@ function listenPing(fn) {
|
|
|
25543
26120
|
* cancel();
|
|
25544
26121
|
* ```
|
|
25545
26122
|
*/
|
|
25546
|
-
function
|
|
25547
|
-
backtest$1.loggerService.log(
|
|
25548
|
-
return
|
|
26123
|
+
function listenSchedulePingOnce(filterFn, fn) {
|
|
26124
|
+
backtest$1.loggerService.log(LISTEN_SCHEDULE_PING_ONCE_METHOD_NAME);
|
|
26125
|
+
return schedulePingSubject.filter(filterFn).once(fn);
|
|
26126
|
+
}
|
|
26127
|
+
/**
|
|
26128
|
+
* Subscribes to active ping events with queued async processing.
|
|
26129
|
+
*
|
|
26130
|
+
* Listens for active pending signal monitoring events emitted every minute.
|
|
26131
|
+
* Useful for tracking active signal lifecycle and implementing dynamic management logic.
|
|
26132
|
+
*
|
|
26133
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
26134
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
26135
|
+
*
|
|
26136
|
+
* @param fn - Callback function to handle active ping events
|
|
26137
|
+
* @returns Unsubscribe function to stop listening
|
|
26138
|
+
*
|
|
26139
|
+
* @example
|
|
26140
|
+
* ```typescript
|
|
26141
|
+
* import { listenActivePing } from "./function/event";
|
|
26142
|
+
*
|
|
26143
|
+
* const unsubscribe = listenActivePing((event) => {
|
|
26144
|
+
* console.log(`[${event.backtest ? "Backtest" : "Live"}] Active Ping`);
|
|
26145
|
+
* console.log(`Symbol: ${event.symbol}, Strategy: ${event.strategyName}`);
|
|
26146
|
+
* console.log(`Signal ID: ${event.data.id}, Position: ${event.data.position}`);
|
|
26147
|
+
* console.log(`Timestamp: ${new Date(event.timestamp).toISOString()}`);
|
|
26148
|
+
* });
|
|
26149
|
+
*
|
|
26150
|
+
* // Later: stop listening
|
|
26151
|
+
* unsubscribe();
|
|
26152
|
+
* ```
|
|
26153
|
+
*/
|
|
26154
|
+
function listenActivePing(fn) {
|
|
26155
|
+
backtest$1.loggerService.log(LISTEN_ACTIVE_PING_METHOD_NAME);
|
|
26156
|
+
return activePingSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
26157
|
+
}
|
|
26158
|
+
/**
|
|
26159
|
+
* Subscribes to filtered active ping events with one-time execution.
|
|
26160
|
+
*
|
|
26161
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
26162
|
+
* and automatically unsubscribes. Useful for waiting for specific active ping conditions.
|
|
26163
|
+
*
|
|
26164
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
26165
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
26166
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
26167
|
+
*
|
|
26168
|
+
* @example
|
|
26169
|
+
* ```typescript
|
|
26170
|
+
* import { listenActivePingOnce } from "./function/event";
|
|
26171
|
+
*
|
|
26172
|
+
* // Wait for first active ping on BTCUSDT
|
|
26173
|
+
* listenActivePingOnce(
|
|
26174
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
26175
|
+
* (event) => console.log("First BTCUSDT active ping received")
|
|
26176
|
+
* );
|
|
26177
|
+
*
|
|
26178
|
+
* // Wait for active ping in backtest mode
|
|
26179
|
+
* const cancel = listenActivePingOnce(
|
|
26180
|
+
* (event) => event.backtest === true,
|
|
26181
|
+
* (event) => console.log("Backtest active ping received at", new Date(event.timestamp))
|
|
26182
|
+
* );
|
|
26183
|
+
*
|
|
26184
|
+
* // Cancel if needed before event fires
|
|
26185
|
+
* cancel();
|
|
26186
|
+
* ```
|
|
26187
|
+
*/
|
|
26188
|
+
function listenActivePingOnce(filterFn, fn) {
|
|
26189
|
+
backtest$1.loggerService.log(LISTEN_ACTIVE_PING_ONCE_METHOD_NAME);
|
|
26190
|
+
return activePingSubject.filter(filterFn).once(fn);
|
|
25549
26191
|
}
|
|
25550
26192
|
|
|
25551
26193
|
const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
@@ -25615,7 +26257,7 @@ const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
|
25615
26257
|
* // ./dump/strategy/{uuid}/06_llm_output.md (final signal)
|
|
25616
26258
|
* ```
|
|
25617
26259
|
*/
|
|
25618
|
-
async function
|
|
26260
|
+
async function dumpSignalData(signalId, history, signal, outputDir = "./dump/strategy") {
|
|
25619
26261
|
backtest$1.loggerService.info(DUMP_SIGNAL_METHOD_NAME, {
|
|
25620
26262
|
signalId,
|
|
25621
26263
|
history,
|
|
@@ -25635,11 +26277,12 @@ const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
|
|
|
25635
26277
|
const BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL = "BacktestUtils.getPendingSignal";
|
|
25636
26278
|
const BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL = "BacktestUtils.getScheduledSignal";
|
|
25637
26279
|
const BACKTEST_METHOD_NAME_GET_BREAKEVEN = "BacktestUtils.getBreakeven";
|
|
25638
|
-
const
|
|
25639
|
-
const
|
|
25640
|
-
const
|
|
25641
|
-
const
|
|
25642
|
-
const
|
|
26280
|
+
const BACKTEST_METHOD_NAME_BREAKEVEN = "Backtest.commitBreakeven";
|
|
26281
|
+
const BACKTEST_METHOD_NAME_CANCEL = "BacktestUtils.commitCancel";
|
|
26282
|
+
const BACKTEST_METHOD_NAME_PARTIAL_PROFIT = "BacktestUtils.commitPartialProfit";
|
|
26283
|
+
const BACKTEST_METHOD_NAME_PARTIAL_LOSS = "BacktestUtils.commitPartialLoss";
|
|
26284
|
+
const BACKTEST_METHOD_NAME_TRAILING_STOP = "BacktestUtils.commitTrailingStop";
|
|
26285
|
+
const BACKTEST_METHOD_NAME_TRAILING_PROFIT = "BacktestUtils.commitTrailingTake";
|
|
25643
26286
|
const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
|
|
25644
26287
|
/**
|
|
25645
26288
|
* Internal task function that runs backtest and handles completion.
|
|
@@ -26163,14 +26806,14 @@ class BacktestUtils {
|
|
|
26163
26806
|
* @example
|
|
26164
26807
|
* ```typescript
|
|
26165
26808
|
* // Cancel scheduled signal with custom ID
|
|
26166
|
-
* await Backtest.
|
|
26809
|
+
* await Backtest.commitCancel("BTCUSDT", "my-strategy", {
|
|
26167
26810
|
* exchangeName: "binance",
|
|
26168
26811
|
* frameName: "frame1",
|
|
26169
26812
|
* strategyName: "my-strategy"
|
|
26170
26813
|
* }, "manual-cancel-001");
|
|
26171
26814
|
* ```
|
|
26172
26815
|
*/
|
|
26173
|
-
this.
|
|
26816
|
+
this.commitCancel = async (symbol, context, cancelId) => {
|
|
26174
26817
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_CANCEL, {
|
|
26175
26818
|
symbol,
|
|
26176
26819
|
context,
|
|
@@ -26208,7 +26851,7 @@ class BacktestUtils {
|
|
|
26208
26851
|
* @example
|
|
26209
26852
|
* ```typescript
|
|
26210
26853
|
* // Close 30% of LONG position at profit
|
|
26211
|
-
* const success = await Backtest.
|
|
26854
|
+
* const success = await Backtest.commitPartialProfit("BTCUSDT", 30, 45000, {
|
|
26212
26855
|
* exchangeName: "binance",
|
|
26213
26856
|
* frameName: "frame1",
|
|
26214
26857
|
* strategyName: "my-strategy"
|
|
@@ -26218,7 +26861,7 @@ class BacktestUtils {
|
|
|
26218
26861
|
* }
|
|
26219
26862
|
* ```
|
|
26220
26863
|
*/
|
|
26221
|
-
this.
|
|
26864
|
+
this.commitPartialProfit = async (symbol, percentToClose, currentPrice, context) => {
|
|
26222
26865
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_PARTIAL_PROFIT, {
|
|
26223
26866
|
symbol,
|
|
26224
26867
|
percentToClose,
|
|
@@ -26257,7 +26900,7 @@ class BacktestUtils {
|
|
|
26257
26900
|
* @example
|
|
26258
26901
|
* ```typescript
|
|
26259
26902
|
* // Close 40% of LONG position at loss
|
|
26260
|
-
* const success = await Backtest.
|
|
26903
|
+
* const success = await Backtest.commitPartialLoss("BTCUSDT", 40, 38000, {
|
|
26261
26904
|
* exchangeName: "binance",
|
|
26262
26905
|
* frameName: "frame1",
|
|
26263
26906
|
* strategyName: "my-strategy"
|
|
@@ -26267,7 +26910,7 @@ class BacktestUtils {
|
|
|
26267
26910
|
* }
|
|
26268
26911
|
* ```
|
|
26269
26912
|
*/
|
|
26270
|
-
this.
|
|
26913
|
+
this.commitPartialLoss = async (symbol, percentToClose, currentPrice, context) => {
|
|
26271
26914
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_PARTIAL_LOSS, {
|
|
26272
26915
|
symbol,
|
|
26273
26916
|
percentToClose,
|
|
@@ -26315,7 +26958,7 @@ class BacktestUtils {
|
|
|
26315
26958
|
* // LONG: entry=100, originalSL=90, distance=10%, currentPrice=102
|
|
26316
26959
|
*
|
|
26317
26960
|
* // First call: tighten by 5%
|
|
26318
|
-
* await Backtest.
|
|
26961
|
+
* await Backtest.commitTrailingStop("BTCUSDT", -5, 102, {
|
|
26319
26962
|
* exchangeName: "binance",
|
|
26320
26963
|
* frameName: "frame1",
|
|
26321
26964
|
* strategyName: "my-strategy"
|
|
@@ -26323,15 +26966,15 @@ class BacktestUtils {
|
|
|
26323
26966
|
* // newDistance = 10% - 5% = 5%, newSL = 95
|
|
26324
26967
|
*
|
|
26325
26968
|
* // Second call: try weaker protection (smaller percentShift)
|
|
26326
|
-
* await Backtest.
|
|
26969
|
+
* await Backtest.commitTrailingStop("BTCUSDT", -3, 102, context);
|
|
26327
26970
|
* // SKIPPED: newSL=97 < 95 (worse protection, larger % absorbs smaller)
|
|
26328
26971
|
*
|
|
26329
26972
|
* // Third call: stronger protection (larger percentShift)
|
|
26330
|
-
* await Backtest.
|
|
26973
|
+
* await Backtest.commitTrailingStop("BTCUSDT", -7, 102, context);
|
|
26331
26974
|
* // ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95 (better protection)
|
|
26332
26975
|
* ```
|
|
26333
26976
|
*/
|
|
26334
|
-
this.
|
|
26977
|
+
this.commitTrailingStop = async (symbol, percentShift, currentPrice, context) => {
|
|
26335
26978
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_TRAILING_STOP, {
|
|
26336
26979
|
symbol,
|
|
26337
26980
|
percentShift,
|
|
@@ -26379,7 +27022,7 @@ class BacktestUtils {
|
|
|
26379
27022
|
* // LONG: entry=100, originalTP=110, distance=10%, currentPrice=102
|
|
26380
27023
|
*
|
|
26381
27024
|
* // First call: bring TP closer by 3%
|
|
26382
|
-
* await Backtest.
|
|
27025
|
+
* await Backtest.commitTrailingTake("BTCUSDT", -3, 102, {
|
|
26383
27026
|
* exchangeName: "binance",
|
|
26384
27027
|
* frameName: "frame1",
|
|
26385
27028
|
* strategyName: "my-strategy"
|
|
@@ -26387,15 +27030,15 @@ class BacktestUtils {
|
|
|
26387
27030
|
* // newDistance = 10% - 3% = 7%, newTP = 107
|
|
26388
27031
|
*
|
|
26389
27032
|
* // Second call: try to move TP further (less conservative)
|
|
26390
|
-
* await Backtest.
|
|
27033
|
+
* await Backtest.commitTrailingTake("BTCUSDT", 2, 102, context);
|
|
26391
27034
|
* // SKIPPED: newTP=112 > 107 (less conservative, larger % absorbs smaller)
|
|
26392
27035
|
*
|
|
26393
27036
|
* // Third call: even more conservative
|
|
26394
|
-
* await Backtest.
|
|
27037
|
+
* await Backtest.commitTrailingTake("BTCUSDT", -5, 102, context);
|
|
26395
27038
|
* // ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107 (more conservative)
|
|
26396
27039
|
* ```
|
|
26397
27040
|
*/
|
|
26398
|
-
this.
|
|
27041
|
+
this.commitTrailingTake = async (symbol, percentShift, currentPrice, context) => {
|
|
26399
27042
|
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_TRAILING_PROFIT, {
|
|
26400
27043
|
symbol,
|
|
26401
27044
|
percentShift,
|
|
@@ -26428,7 +27071,7 @@ class BacktestUtils {
|
|
|
26428
27071
|
*
|
|
26429
27072
|
* @example
|
|
26430
27073
|
* ```typescript
|
|
26431
|
-
* const moved = await Backtest.
|
|
27074
|
+
* const moved = await Backtest.commitBreakeven(
|
|
26432
27075
|
* "BTCUSDT",
|
|
26433
27076
|
* 112,
|
|
26434
27077
|
* { strategyName: "my-strategy", exchangeName: "binance", frameName: "1h" }
|
|
@@ -26436,22 +27079,22 @@ class BacktestUtils {
|
|
|
26436
27079
|
* console.log(moved); // true (SL moved to entry price)
|
|
26437
27080
|
* ```
|
|
26438
27081
|
*/
|
|
26439
|
-
this.
|
|
26440
|
-
backtest$1.loggerService.info(
|
|
27082
|
+
this.commitBreakeven = async (symbol, currentPrice, context) => {
|
|
27083
|
+
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_BREAKEVEN, {
|
|
26441
27084
|
symbol,
|
|
26442
27085
|
currentPrice,
|
|
26443
27086
|
context,
|
|
26444
27087
|
});
|
|
26445
|
-
backtest$1.strategyValidationService.validate(context.strategyName,
|
|
26446
|
-
backtest$1.exchangeValidationService.validate(context.exchangeName,
|
|
27088
|
+
backtest$1.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_BREAKEVEN);
|
|
27089
|
+
backtest$1.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_BREAKEVEN);
|
|
26447
27090
|
{
|
|
26448
27091
|
const { riskName, riskList, actions } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
26449
27092
|
riskName &&
|
|
26450
|
-
backtest$1.riskValidationService.validate(riskName,
|
|
27093
|
+
backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_BREAKEVEN);
|
|
26451
27094
|
riskList &&
|
|
26452
|
-
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName,
|
|
27095
|
+
riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_BREAKEVEN));
|
|
26453
27096
|
actions &&
|
|
26454
|
-
actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName,
|
|
27097
|
+
actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_BREAKEVEN));
|
|
26455
27098
|
}
|
|
26456
27099
|
return await backtest$1.strategyCoreService.breakeven(true, symbol, currentPrice, context);
|
|
26457
27100
|
};
|
|
@@ -26623,11 +27266,12 @@ const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
|
|
|
26623
27266
|
const LIVE_METHOD_NAME_GET_PENDING_SIGNAL = "LiveUtils.getPendingSignal";
|
|
26624
27267
|
const LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL = "LiveUtils.getScheduledSignal";
|
|
26625
27268
|
const LIVE_METHOD_NAME_GET_BREAKEVEN = "LiveUtils.getBreakeven";
|
|
26626
|
-
const
|
|
26627
|
-
const
|
|
26628
|
-
const
|
|
26629
|
-
const
|
|
26630
|
-
const
|
|
27269
|
+
const LIVE_METHOD_NAME_BREAKEVEN = "Live.commitBreakeven";
|
|
27270
|
+
const LIVE_METHOD_NAME_CANCEL = "LiveUtils.commitCancel";
|
|
27271
|
+
const LIVE_METHOD_NAME_PARTIAL_PROFIT = "LiveUtils.commitPartialProfit";
|
|
27272
|
+
const LIVE_METHOD_NAME_PARTIAL_LOSS = "LiveUtils.commitPartialLoss";
|
|
27273
|
+
const LIVE_METHOD_NAME_TRAILING_STOP = "LiveUtils.commitTrailingStop";
|
|
27274
|
+
const LIVE_METHOD_NAME_TRAILING_PROFIT = "LiveUtils.commitTrailingTake";
|
|
26631
27275
|
/**
|
|
26632
27276
|
* Internal task function that runs live trading and handles completion.
|
|
26633
27277
|
* Consumes live trading results and updates instance state flags.
|
|
@@ -27117,14 +27761,14 @@ class LiveUtils {
|
|
|
27117
27761
|
* @example
|
|
27118
27762
|
* ```typescript
|
|
27119
27763
|
* // Cancel scheduled signal in live trading with custom ID
|
|
27120
|
-
* await Live.
|
|
27764
|
+
* await Live.commitCancel("BTCUSDT", "my-strategy", {
|
|
27121
27765
|
* exchangeName: "binance",
|
|
27122
27766
|
* frameName: "",
|
|
27123
27767
|
* strategyName: "my-strategy"
|
|
27124
27768
|
* }, "manual-cancel-001");
|
|
27125
27769
|
* ```
|
|
27126
27770
|
*/
|
|
27127
|
-
this.
|
|
27771
|
+
this.commitCancel = async (symbol, context, cancelId) => {
|
|
27128
27772
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_CANCEL, {
|
|
27129
27773
|
symbol,
|
|
27130
27774
|
context,
|
|
@@ -27163,7 +27807,7 @@ class LiveUtils {
|
|
|
27163
27807
|
* @example
|
|
27164
27808
|
* ```typescript
|
|
27165
27809
|
* // Close 30% of LONG position at profit
|
|
27166
|
-
* const success = await Live.
|
|
27810
|
+
* const success = await Live.commitPartialProfit("BTCUSDT", 30, 45000, {
|
|
27167
27811
|
* exchangeName: "binance",
|
|
27168
27812
|
* strategyName: "my-strategy"
|
|
27169
27813
|
* });
|
|
@@ -27172,7 +27816,7 @@ class LiveUtils {
|
|
|
27172
27816
|
* }
|
|
27173
27817
|
* ```
|
|
27174
27818
|
*/
|
|
27175
|
-
this.
|
|
27819
|
+
this.commitPartialProfit = async (symbol, percentToClose, currentPrice, context) => {
|
|
27176
27820
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_PARTIAL_PROFIT, {
|
|
27177
27821
|
symbol,
|
|
27178
27822
|
percentToClose,
|
|
@@ -27212,7 +27856,7 @@ class LiveUtils {
|
|
|
27212
27856
|
* @example
|
|
27213
27857
|
* ```typescript
|
|
27214
27858
|
* // Close 40% of LONG position at loss
|
|
27215
|
-
* const success = await Live.
|
|
27859
|
+
* const success = await Live.commitPartialLoss("BTCUSDT", 40, 38000, {
|
|
27216
27860
|
* exchangeName: "binance",
|
|
27217
27861
|
* strategyName: "my-strategy"
|
|
27218
27862
|
* });
|
|
@@ -27221,7 +27865,7 @@ class LiveUtils {
|
|
|
27221
27865
|
* }
|
|
27222
27866
|
* ```
|
|
27223
27867
|
*/
|
|
27224
|
-
this.
|
|
27868
|
+
this.commitPartialLoss = async (symbol, percentToClose, currentPrice, context) => {
|
|
27225
27869
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_PARTIAL_LOSS, {
|
|
27226
27870
|
symbol,
|
|
27227
27871
|
percentToClose,
|
|
@@ -27270,22 +27914,22 @@ class LiveUtils {
|
|
|
27270
27914
|
* // LONG: entry=100, originalSL=90, distance=10%, currentPrice=102
|
|
27271
27915
|
*
|
|
27272
27916
|
* // First call: tighten by 5%
|
|
27273
|
-
* const success1 = await Live.
|
|
27917
|
+
* const success1 = await Live.commitTrailingStop("BTCUSDT", -5, 102, {
|
|
27274
27918
|
* exchangeName: "binance",
|
|
27275
27919
|
* strategyName: "my-strategy"
|
|
27276
27920
|
* });
|
|
27277
27921
|
* // success1 = true, newDistance = 10% - 5% = 5%, newSL = 95
|
|
27278
27922
|
*
|
|
27279
27923
|
* // Second call: try weaker protection (smaller percentShift)
|
|
27280
|
-
* const success2 = await Live.
|
|
27924
|
+
* const success2 = await Live.commitTrailingStop("BTCUSDT", -3, 102, context);
|
|
27281
27925
|
* // success2 = false (SKIPPED: newSL=97 < 95, worse protection, larger % absorbs smaller)
|
|
27282
27926
|
*
|
|
27283
27927
|
* // Third call: stronger protection (larger percentShift)
|
|
27284
|
-
* const success3 = await Live.
|
|
27928
|
+
* const success3 = await Live.commitTrailingStop("BTCUSDT", -7, 102, context);
|
|
27285
27929
|
* // success3 = true (ACCEPTED: newDistance = 10% - 7% = 3%, newSL = 97 > 95, better protection)
|
|
27286
27930
|
* ```
|
|
27287
27931
|
*/
|
|
27288
|
-
this.
|
|
27932
|
+
this.commitTrailingStop = async (symbol, percentShift, currentPrice, context) => {
|
|
27289
27933
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_TRAILING_STOP, {
|
|
27290
27934
|
symbol,
|
|
27291
27935
|
percentShift,
|
|
@@ -27334,22 +27978,22 @@ class LiveUtils {
|
|
|
27334
27978
|
* // LONG: entry=100, originalTP=110, distance=10%, currentPrice=102
|
|
27335
27979
|
*
|
|
27336
27980
|
* // First call: bring TP closer by 3%
|
|
27337
|
-
* const success1 = await Live.
|
|
27981
|
+
* const success1 = await Live.commitTrailingTake("BTCUSDT", -3, 102, {
|
|
27338
27982
|
* exchangeName: "binance",
|
|
27339
27983
|
* strategyName: "my-strategy"
|
|
27340
27984
|
* });
|
|
27341
27985
|
* // success1 = true, newDistance = 10% - 3% = 7%, newTP = 107
|
|
27342
27986
|
*
|
|
27343
27987
|
* // Second call: try to move TP further (less conservative)
|
|
27344
|
-
* const success2 = await Live.
|
|
27988
|
+
* const success2 = await Live.commitTrailingTake("BTCUSDT", 2, 102, context);
|
|
27345
27989
|
* // success2 = false (SKIPPED: newTP=112 > 107, less conservative, larger % absorbs smaller)
|
|
27346
27990
|
*
|
|
27347
27991
|
* // Third call: even more conservative
|
|
27348
|
-
* const success3 = await Live.
|
|
27992
|
+
* const success3 = await Live.commitTrailingTake("BTCUSDT", -5, 102, context);
|
|
27349
27993
|
* // success3 = true (ACCEPTED: newDistance = 10% - 5% = 5%, newTP = 105 < 107, more conservative)
|
|
27350
27994
|
* ```
|
|
27351
27995
|
*/
|
|
27352
|
-
this.
|
|
27996
|
+
this.commitTrailingTake = async (symbol, percentShift, currentPrice, context) => {
|
|
27353
27997
|
backtest$1.loggerService.info(LIVE_METHOD_NAME_TRAILING_PROFIT, {
|
|
27354
27998
|
symbol,
|
|
27355
27999
|
percentShift,
|
|
@@ -27383,7 +28027,7 @@ class LiveUtils {
|
|
|
27383
28027
|
*
|
|
27384
28028
|
* @example
|
|
27385
28029
|
* ```typescript
|
|
27386
|
-
* const moved = await Live.
|
|
28030
|
+
* const moved = await Live.commitBreakeven(
|
|
27387
28031
|
* "BTCUSDT",
|
|
27388
28032
|
* 112,
|
|
27389
28033
|
* { strategyName: "my-strategy", exchangeName: "binance" }
|
|
@@ -27391,19 +28035,19 @@ class LiveUtils {
|
|
|
27391
28035
|
* console.log(moved); // true (SL moved to entry price)
|
|
27392
28036
|
* ```
|
|
27393
28037
|
*/
|
|
27394
|
-
this.
|
|
27395
|
-
backtest$1.loggerService.info(
|
|
28038
|
+
this.commitBreakeven = async (symbol, currentPrice, context) => {
|
|
28039
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_BREAKEVEN, {
|
|
27396
28040
|
symbol,
|
|
27397
28041
|
currentPrice,
|
|
27398
28042
|
context,
|
|
27399
28043
|
});
|
|
27400
|
-
backtest$1.strategyValidationService.validate(context.strategyName,
|
|
27401
|
-
backtest$1.exchangeValidationService.validate(context.exchangeName,
|
|
28044
|
+
backtest$1.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_BREAKEVEN);
|
|
28045
|
+
backtest$1.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_BREAKEVEN);
|
|
27402
28046
|
{
|
|
27403
28047
|
const { riskName, riskList, actions } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
27404
|
-
riskName && backtest$1.riskValidationService.validate(riskName,
|
|
27405
|
-
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName,
|
|
27406
|
-
actions && actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName,
|
|
28048
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_BREAKEVEN);
|
|
28049
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_BREAKEVEN));
|
|
28050
|
+
actions && actions.forEach((actionName) => backtest$1.actionValidationService.validate(actionName, LIVE_METHOD_NAME_BREAKEVEN));
|
|
27407
28051
|
}
|
|
27408
28052
|
return await backtest$1.strategyCoreService.breakeven(false, symbol, currentPrice, {
|
|
27409
28053
|
strategyName: context.strategyName,
|
|
@@ -29231,10 +29875,15 @@ class ExchangeInstance {
|
|
|
29231
29875
|
const whenTimestamp = when.getTime();
|
|
29232
29876
|
const sinceTimestamp = since.getTime();
|
|
29233
29877
|
const filteredData = allData.filter((candle) => candle.timestamp >= sinceTimestamp && candle.timestamp <= whenTimestamp);
|
|
29234
|
-
|
|
29235
|
-
|
|
29878
|
+
// Apply distinct by timestamp to remove duplicates
|
|
29879
|
+
const uniqueData = Array.from(new Map(filteredData.map((candle) => [candle.timestamp, candle])).values());
|
|
29880
|
+
if (filteredData.length !== uniqueData.length) {
|
|
29881
|
+
backtest$1.loggerService.warn(`ExchangeInstance Removed ${filteredData.length - uniqueData.length} duplicate candles by timestamp`);
|
|
29236
29882
|
}
|
|
29237
|
-
|
|
29883
|
+
if (uniqueData.length < limit) {
|
|
29884
|
+
backtest$1.loggerService.warn(`ExchangeInstance Expected ${limit} candles, got ${uniqueData.length}`);
|
|
29885
|
+
}
|
|
29886
|
+
return uniqueData;
|
|
29238
29887
|
};
|
|
29239
29888
|
/**
|
|
29240
29889
|
* Calculates VWAP (Volume Weighted Average Price) from last N 1m candles.
|
|
@@ -30413,10 +31062,11 @@ const METHOD_NAME_INIT = "ActionBase.init";
|
|
|
30413
31062
|
const METHOD_NAME_EVENT = "ActionBase.event";
|
|
30414
31063
|
const METHOD_NAME_SIGNAL_LIVE = "ActionBase.signalLive";
|
|
30415
31064
|
const METHOD_NAME_SIGNAL_BACKTEST = "ActionBase.signalBacktest";
|
|
30416
|
-
const
|
|
30417
|
-
const
|
|
30418
|
-
const
|
|
30419
|
-
const
|
|
31065
|
+
const METHOD_NAME_BREAKEVEN_AVAILABLE = "ActionBase.breakevenAvailable";
|
|
31066
|
+
const METHOD_NAME_PARTIAL_PROFIT_AVAILABLE = "ActionBase.partialProfitAvailable";
|
|
31067
|
+
const METHOD_NAME_PARTIAL_LOSS_AVAILABLE = "ActionBase.partialLossAvailable";
|
|
31068
|
+
const METHOD_NAME_PING_SCHEDULED = "ActionBase.pingScheduled";
|
|
31069
|
+
const METHOD_NAME_PING_ACTIVE = "ActionBase.pingActive";
|
|
30420
31070
|
const METHOD_NAME_RISK_REJECTION = "ActionBase.riskRejection";
|
|
30421
31071
|
const METHOD_NAME_DISPOSE = "ActionBase.dispose";
|
|
30422
31072
|
const DEFAULT_SOURCE = "default";
|
|
@@ -30447,10 +31097,11 @@ const DEFAULT_SOURCE = "default";
|
|
|
30447
31097
|
* - signal() - Called on every tick/candle (all modes)
|
|
30448
31098
|
* - signalLive() - Called only in live mode
|
|
30449
31099
|
* - signalBacktest() - Called only in backtest mode
|
|
30450
|
-
* -
|
|
30451
|
-
* -
|
|
30452
|
-
* -
|
|
30453
|
-
* -
|
|
31100
|
+
* - breakevenAvailable() - Called when SL moved to entry
|
|
31101
|
+
* - partialProfitAvailable() - Called on profit milestones (10%, 20%, etc.)
|
|
31102
|
+
* - partialLossAvailable() - Called on loss milestones (-10%, -20%, etc.)
|
|
31103
|
+
* - pingScheduled() - Called every minute during scheduled signal monitoring
|
|
31104
|
+
* - pingActive() - Called every minute during active pending signal monitoring
|
|
30454
31105
|
* - riskRejection() - Called when signal rejected by risk management
|
|
30455
31106
|
*
|
|
30456
31107
|
* @example
|
|
@@ -30491,7 +31142,7 @@ const DEFAULT_SOURCE = "default";
|
|
|
30491
31142
|
* }
|
|
30492
31143
|
*
|
|
30493
31144
|
* // Register the action
|
|
30494
|
-
*
|
|
31145
|
+
* addActionSchema({
|
|
30495
31146
|
* actionName: "telegram-notifier",
|
|
30496
31147
|
* handler: TelegramNotifier
|
|
30497
31148
|
* });
|
|
@@ -30533,11 +31184,13 @@ class ActionBase {
|
|
|
30533
31184
|
* @param strategyName - Strategy identifier this action is attached to
|
|
30534
31185
|
* @param frameName - Timeframe identifier this action is attached to
|
|
30535
31186
|
* @param actionName - Action identifier
|
|
31187
|
+
* @param backtest - If running in backtest
|
|
30536
31188
|
*/
|
|
30537
|
-
constructor(strategyName, frameName, actionName) {
|
|
31189
|
+
constructor(strategyName, frameName, actionName, backtest) {
|
|
30538
31190
|
this.strategyName = strategyName;
|
|
30539
31191
|
this.frameName = frameName;
|
|
30540
31192
|
this.actionName = actionName;
|
|
31193
|
+
this.backtest = backtest;
|
|
30541
31194
|
}
|
|
30542
31195
|
/**
|
|
30543
31196
|
* Initializes the action handler.
|
|
@@ -30661,7 +31314,7 @@ class ActionBase {
|
|
|
30661
31314
|
* Called once per signal when price moves far enough to cover fees and slippage.
|
|
30662
31315
|
* Breakeven threshold: (CC_PERCENT_SLIPPAGE + CC_PERCENT_FEE) * 2 + CC_BREAKEVEN_THRESHOLD
|
|
30663
31316
|
*
|
|
30664
|
-
* Triggered by: ActionCoreService.
|
|
31317
|
+
* Triggered by: ActionCoreService.breakevenAvailable() via BreakevenConnectionService
|
|
30665
31318
|
* Source: breakevenSubject.next() in CREATE_COMMIT_BREAKEVEN_FN callback
|
|
30666
31319
|
* Frequency: Once per signal when threshold reached
|
|
30667
31320
|
*
|
|
@@ -30671,7 +31324,7 @@ class ActionBase {
|
|
|
30671
31324
|
*
|
|
30672
31325
|
* @example
|
|
30673
31326
|
* ```typescript
|
|
30674
|
-
* async
|
|
31327
|
+
* async breakevenAvailable(event: BreakevenContract) {
|
|
30675
31328
|
* await this.telegram.send(
|
|
30676
31329
|
* `[${event.strategyName}] Breakeven reached! ` +
|
|
30677
31330
|
* `Signal: ${event.data.side} @ ${event.currentPrice}`
|
|
@@ -30679,8 +31332,8 @@ class ActionBase {
|
|
|
30679
31332
|
* }
|
|
30680
31333
|
* ```
|
|
30681
31334
|
*/
|
|
30682
|
-
|
|
30683
|
-
backtest$1.loggerService.info(
|
|
31335
|
+
breakevenAvailable(event, source = DEFAULT_SOURCE) {
|
|
31336
|
+
backtest$1.loggerService.info(METHOD_NAME_BREAKEVEN_AVAILABLE, {
|
|
30684
31337
|
event,
|
|
30685
31338
|
source,
|
|
30686
31339
|
});
|
|
@@ -30691,7 +31344,7 @@ class ActionBase {
|
|
|
30691
31344
|
* Called once per profit level per signal (deduplicated).
|
|
30692
31345
|
* Use to track profit milestones and adjust position management.
|
|
30693
31346
|
*
|
|
30694
|
-
* Triggered by: ActionCoreService.
|
|
31347
|
+
* Triggered by: ActionCoreService.partialProfitAvailable() via PartialConnectionService
|
|
30695
31348
|
* Source: partialProfitSubject.next() in CREATE_COMMIT_PROFIT_FN callback
|
|
30696
31349
|
* Frequency: Once per profit level per signal
|
|
30697
31350
|
*
|
|
@@ -30701,7 +31354,7 @@ class ActionBase {
|
|
|
30701
31354
|
*
|
|
30702
31355
|
* @example
|
|
30703
31356
|
* ```typescript
|
|
30704
|
-
* async
|
|
31357
|
+
* async partialProfitAvailable(event: PartialProfitContract) {
|
|
30705
31358
|
* await this.telegram.send(
|
|
30706
31359
|
* `[${event.strategyName}] Profit ${event.level}% reached! ` +
|
|
30707
31360
|
* `Current price: ${event.currentPrice}`
|
|
@@ -30710,8 +31363,8 @@ class ActionBase {
|
|
|
30710
31363
|
* }
|
|
30711
31364
|
* ```
|
|
30712
31365
|
*/
|
|
30713
|
-
|
|
30714
|
-
backtest$1.loggerService.info(
|
|
31366
|
+
partialProfitAvailable(event, source = DEFAULT_SOURCE) {
|
|
31367
|
+
backtest$1.loggerService.info(METHOD_NAME_PARTIAL_PROFIT_AVAILABLE, {
|
|
30715
31368
|
event,
|
|
30716
31369
|
source,
|
|
30717
31370
|
});
|
|
@@ -30722,7 +31375,7 @@ class ActionBase {
|
|
|
30722
31375
|
* Called once per loss level per signal (deduplicated).
|
|
30723
31376
|
* Use to track loss milestones and implement risk management actions.
|
|
30724
31377
|
*
|
|
30725
|
-
* Triggered by: ActionCoreService.
|
|
31378
|
+
* Triggered by: ActionCoreService.partialLossAvailable() via PartialConnectionService
|
|
30726
31379
|
* Source: partialLossSubject.next() in CREATE_COMMIT_LOSS_FN callback
|
|
30727
31380
|
* Frequency: Once per loss level per signal
|
|
30728
31381
|
*
|
|
@@ -30732,7 +31385,7 @@ class ActionBase {
|
|
|
30732
31385
|
*
|
|
30733
31386
|
* @example
|
|
30734
31387
|
* ```typescript
|
|
30735
|
-
* async
|
|
31388
|
+
* async partialLossAvailable(event: PartialLossContract) {
|
|
30736
31389
|
* await this.telegram.send(
|
|
30737
31390
|
* `[${event.strategyName}] Loss ${event.level}% reached! ` +
|
|
30738
31391
|
* `Current price: ${event.currentPrice}`
|
|
@@ -30741,37 +31394,66 @@ class ActionBase {
|
|
|
30741
31394
|
* }
|
|
30742
31395
|
* ```
|
|
30743
31396
|
*/
|
|
30744
|
-
|
|
30745
|
-
backtest$1.loggerService.info(
|
|
31397
|
+
partialLossAvailable(event, source = DEFAULT_SOURCE) {
|
|
31398
|
+
backtest$1.loggerService.info(METHOD_NAME_PARTIAL_LOSS_AVAILABLE, {
|
|
30746
31399
|
event,
|
|
30747
31400
|
source,
|
|
30748
31401
|
});
|
|
30749
31402
|
}
|
|
30750
31403
|
/**
|
|
30751
|
-
* Handles ping events during scheduled signal monitoring.
|
|
31404
|
+
* Handles scheduled ping events during scheduled signal monitoring.
|
|
30752
31405
|
*
|
|
30753
31406
|
* Called every minute while a scheduled signal is waiting for activation.
|
|
30754
31407
|
* Use to monitor pending signals and track wait time.
|
|
30755
31408
|
*
|
|
30756
|
-
* Triggered by: ActionCoreService.
|
|
30757
|
-
* Source:
|
|
31409
|
+
* Triggered by: ActionCoreService.pingScheduled() via StrategyConnectionService
|
|
31410
|
+
* Source: schedulePingSubject.next() in CREATE_COMMIT_SCHEDULE_PING_FN callback
|
|
30758
31411
|
* Frequency: Every minute while scheduled signal is waiting
|
|
30759
31412
|
*
|
|
30760
|
-
* Default implementation: Logs ping event.
|
|
31413
|
+
* Default implementation: Logs scheduled ping event.
|
|
30761
31414
|
*
|
|
30762
31415
|
* @param event - Scheduled signal monitoring data with symbol, strategy info, signal data, timestamp
|
|
30763
31416
|
*
|
|
30764
31417
|
* @example
|
|
30765
31418
|
* ```typescript
|
|
30766
|
-
*
|
|
31419
|
+
* pingScheduled(event: SchedulePingContract) {
|
|
30767
31420
|
* const waitTime = Date.now() - event.data.timestampScheduled;
|
|
30768
31421
|
* const waitMinutes = Math.floor(waitTime / 60000);
|
|
30769
31422
|
* console.log(`Scheduled signal waiting ${waitMinutes} minutes`);
|
|
30770
31423
|
* }
|
|
30771
31424
|
* ```
|
|
30772
31425
|
*/
|
|
30773
|
-
|
|
30774
|
-
backtest$1.loggerService.info(
|
|
31426
|
+
pingScheduled(event, source = DEFAULT_SOURCE) {
|
|
31427
|
+
backtest$1.loggerService.info(METHOD_NAME_PING_SCHEDULED, {
|
|
31428
|
+
event,
|
|
31429
|
+
source,
|
|
31430
|
+
});
|
|
31431
|
+
}
|
|
31432
|
+
/**
|
|
31433
|
+
* Handles active ping events during active pending signal monitoring.
|
|
31434
|
+
*
|
|
31435
|
+
* Called every minute while a pending signal is active (position open).
|
|
31436
|
+
* Use to monitor active positions and track lifecycle.
|
|
31437
|
+
*
|
|
31438
|
+
* Triggered by: ActionCoreService.pingActive() via StrategyConnectionService
|
|
31439
|
+
* Source: activePingSubject.next() in CREATE_COMMIT_ACTIVE_PING_FN callback
|
|
31440
|
+
* Frequency: Every minute while pending signal is active
|
|
31441
|
+
*
|
|
31442
|
+
* Default implementation: Logs active ping event.
|
|
31443
|
+
*
|
|
31444
|
+
* @param event - Active pending signal monitoring data with symbol, strategy info, signal data, timestamp
|
|
31445
|
+
*
|
|
31446
|
+
* @example
|
|
31447
|
+
* ```typescript
|
|
31448
|
+
* pingActive(event: ActivePingContract) {
|
|
31449
|
+
* const holdTime = Date.now() - event.data.pendingAt;
|
|
31450
|
+
* const holdMinutes = Math.floor(holdTime / 60000);
|
|
31451
|
+
* console.log(`Active signal holding ${holdMinutes} minutes`);
|
|
31452
|
+
* }
|
|
31453
|
+
* ```
|
|
31454
|
+
*/
|
|
31455
|
+
pingActive(event, source = DEFAULT_SOURCE) {
|
|
31456
|
+
backtest$1.loggerService.info(METHOD_NAME_PING_ACTIVE, {
|
|
30775
31457
|
event,
|
|
30776
31458
|
source,
|
|
30777
31459
|
});
|
|
@@ -30919,42 +31601,59 @@ exports.ReportBase = ReportBase;
|
|
|
30919
31601
|
exports.Risk = Risk;
|
|
30920
31602
|
exports.Schedule = Schedule;
|
|
30921
31603
|
exports.Walker = Walker;
|
|
30922
|
-
exports.
|
|
30923
|
-
exports.
|
|
30924
|
-
exports.
|
|
30925
|
-
exports.
|
|
30926
|
-
exports.
|
|
30927
|
-
exports.
|
|
30928
|
-
exports.
|
|
30929
|
-
exports.
|
|
30930
|
-
exports.
|
|
30931
|
-
exports.
|
|
30932
|
-
exports.
|
|
31604
|
+
exports.addActionSchema = addActionSchema;
|
|
31605
|
+
exports.addExchangeSchema = addExchangeSchema;
|
|
31606
|
+
exports.addFrameSchema = addFrameSchema;
|
|
31607
|
+
exports.addOptimizerSchema = addOptimizerSchema;
|
|
31608
|
+
exports.addRiskSchema = addRiskSchema;
|
|
31609
|
+
exports.addSizingSchema = addSizingSchema;
|
|
31610
|
+
exports.addStrategySchema = addStrategySchema;
|
|
31611
|
+
exports.addWalkerSchema = addWalkerSchema;
|
|
31612
|
+
exports.commitBreakeven = commitBreakeven;
|
|
31613
|
+
exports.commitCancel = commitCancel;
|
|
31614
|
+
exports.commitPartialLoss = commitPartialLoss;
|
|
31615
|
+
exports.commitPartialProfit = commitPartialProfit;
|
|
31616
|
+
exports.commitTrailingStop = commitTrailingStop;
|
|
31617
|
+
exports.commitTrailingTake = commitTrailingTake;
|
|
31618
|
+
exports.dumpSignalData = dumpSignalData;
|
|
30933
31619
|
exports.emitters = emitters;
|
|
30934
31620
|
exports.formatPrice = formatPrice;
|
|
30935
31621
|
exports.formatQuantity = formatQuantity;
|
|
30936
31622
|
exports.get = get;
|
|
31623
|
+
exports.getActionSchema = getActionSchema;
|
|
30937
31624
|
exports.getAveragePrice = getAveragePrice;
|
|
31625
|
+
exports.getBacktestTimeframe = getBacktestTimeframe;
|
|
30938
31626
|
exports.getCandles = getCandles;
|
|
30939
31627
|
exports.getColumns = getColumns;
|
|
30940
31628
|
exports.getConfig = getConfig;
|
|
31629
|
+
exports.getContext = getContext;
|
|
30941
31630
|
exports.getDate = getDate;
|
|
30942
31631
|
exports.getDefaultColumns = getDefaultColumns;
|
|
30943
31632
|
exports.getDefaultConfig = getDefaultConfig;
|
|
31633
|
+
exports.getExchangeSchema = getExchangeSchema;
|
|
31634
|
+
exports.getFrameSchema = getFrameSchema;
|
|
30944
31635
|
exports.getMode = getMode;
|
|
31636
|
+
exports.getOptimizerSchema = getOptimizerSchema;
|
|
30945
31637
|
exports.getOrderBook = getOrderBook;
|
|
31638
|
+
exports.getRiskSchema = getRiskSchema;
|
|
31639
|
+
exports.getSizingSchema = getSizingSchema;
|
|
31640
|
+
exports.getStrategySchema = getStrategySchema;
|
|
31641
|
+
exports.getSymbol = getSymbol;
|
|
31642
|
+
exports.getWalkerSchema = getWalkerSchema;
|
|
30946
31643
|
exports.hasTradeContext = hasTradeContext;
|
|
30947
31644
|
exports.lib = backtest;
|
|
30948
|
-
exports.
|
|
30949
|
-
exports.
|
|
30950
|
-
exports.
|
|
30951
|
-
exports.
|
|
30952
|
-
exports.
|
|
30953
|
-
exports.
|
|
30954
|
-
exports.
|
|
31645
|
+
exports.listExchangeSchema = listExchangeSchema;
|
|
31646
|
+
exports.listFrameSchema = listFrameSchema;
|
|
31647
|
+
exports.listOptimizerSchema = listOptimizerSchema;
|
|
31648
|
+
exports.listRiskSchema = listRiskSchema;
|
|
31649
|
+
exports.listSizingSchema = listSizingSchema;
|
|
31650
|
+
exports.listStrategySchema = listStrategySchema;
|
|
31651
|
+
exports.listWalkerSchema = listWalkerSchema;
|
|
31652
|
+
exports.listenActivePing = listenActivePing;
|
|
31653
|
+
exports.listenActivePingOnce = listenActivePingOnce;
|
|
30955
31654
|
exports.listenBacktestProgress = listenBacktestProgress;
|
|
30956
|
-
exports.
|
|
30957
|
-
exports.
|
|
31655
|
+
exports.listenBreakevenAvailable = listenBreakevenAvailable;
|
|
31656
|
+
exports.listenBreakevenAvailableOnce = listenBreakevenAvailableOnce;
|
|
30958
31657
|
exports.listenDoneBacktest = listenDoneBacktest;
|
|
30959
31658
|
exports.listenDoneBacktestOnce = listenDoneBacktestOnce;
|
|
30960
31659
|
exports.listenDoneLive = listenDoneLive;
|
|
@@ -30964,15 +31663,15 @@ exports.listenDoneWalkerOnce = listenDoneWalkerOnce;
|
|
|
30964
31663
|
exports.listenError = listenError;
|
|
30965
31664
|
exports.listenExit = listenExit;
|
|
30966
31665
|
exports.listenOptimizerProgress = listenOptimizerProgress;
|
|
30967
|
-
exports.
|
|
30968
|
-
exports.
|
|
30969
|
-
exports.
|
|
30970
|
-
exports.
|
|
31666
|
+
exports.listenPartialLossAvailable = listenPartialLossAvailable;
|
|
31667
|
+
exports.listenPartialLossAvailableOnce = listenPartialLossAvailableOnce;
|
|
31668
|
+
exports.listenPartialProfitAvailable = listenPartialProfitAvailable;
|
|
31669
|
+
exports.listenPartialProfitAvailableOnce = listenPartialProfitAvailableOnce;
|
|
30971
31670
|
exports.listenPerformance = listenPerformance;
|
|
30972
|
-
exports.listenPing = listenPing;
|
|
30973
|
-
exports.listenPingOnce = listenPingOnce;
|
|
30974
31671
|
exports.listenRisk = listenRisk;
|
|
30975
31672
|
exports.listenRiskOnce = listenRiskOnce;
|
|
31673
|
+
exports.listenSchedulePing = listenSchedulePing;
|
|
31674
|
+
exports.listenSchedulePingOnce = listenSchedulePingOnce;
|
|
30976
31675
|
exports.listenSignal = listenSignal;
|
|
30977
31676
|
exports.listenSignalBacktest = listenSignalBacktest;
|
|
30978
31677
|
exports.listenSignalBacktestOnce = listenSignalBacktestOnce;
|
|
@@ -30984,22 +31683,18 @@ exports.listenWalker = listenWalker;
|
|
|
30984
31683
|
exports.listenWalkerComplete = listenWalkerComplete;
|
|
30985
31684
|
exports.listenWalkerOnce = listenWalkerOnce;
|
|
30986
31685
|
exports.listenWalkerProgress = listenWalkerProgress;
|
|
30987
|
-
exports.
|
|
30988
|
-
exports.
|
|
30989
|
-
exports.
|
|
30990
|
-
exports.
|
|
30991
|
-
exports.
|
|
30992
|
-
exports.
|
|
30993
|
-
exports.
|
|
30994
|
-
exports.
|
|
30995
|
-
exports.partialLoss = partialLoss;
|
|
30996
|
-
exports.partialProfit = partialProfit;
|
|
31686
|
+
exports.overrideActionSchema = overrideActionSchema;
|
|
31687
|
+
exports.overrideExchangeSchema = overrideExchangeSchema;
|
|
31688
|
+
exports.overrideFrameSchema = overrideFrameSchema;
|
|
31689
|
+
exports.overrideOptimizerSchema = overrideOptimizerSchema;
|
|
31690
|
+
exports.overrideRiskSchema = overrideRiskSchema;
|
|
31691
|
+
exports.overrideSizingSchema = overrideSizingSchema;
|
|
31692
|
+
exports.overrideStrategySchema = overrideStrategySchema;
|
|
31693
|
+
exports.overrideWalkerSchema = overrideWalkerSchema;
|
|
30997
31694
|
exports.roundTicks = roundTicks;
|
|
30998
31695
|
exports.set = set;
|
|
30999
31696
|
exports.setColumns = setColumns;
|
|
31000
31697
|
exports.setConfig = setConfig;
|
|
31001
31698
|
exports.setLogger = setLogger;
|
|
31002
31699
|
exports.stop = stop;
|
|
31003
|
-
exports.trailingStop = trailingStop;
|
|
31004
|
-
exports.trailingTake = trailingTake;
|
|
31005
31700
|
exports.validate = validate;
|