backtest-kit 1.5.47 → 1.6.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/build/index.cjs +648 -12
- package/build/index.mjs +647 -13
- package/package.json +1 -1
- package/types.d.ts +322 -2
package/build/index.mjs
CHANGED
|
@@ -1744,6 +1744,12 @@ const partialLossSubject = new Subject();
|
|
|
1744
1744
|
* Does not emit for allowed signals (prevents spam).
|
|
1745
1745
|
*/
|
|
1746
1746
|
const riskSubject = new Subject();
|
|
1747
|
+
/**
|
|
1748
|
+
* Ping emitter for scheduled signal monitoring events.
|
|
1749
|
+
* Emits every minute when a scheduled signal is being monitored (waiting for activation).
|
|
1750
|
+
* Allows users to track scheduled signal lifecycle and implement custom cancellation logic.
|
|
1751
|
+
*/
|
|
1752
|
+
const pingSubject = new Subject();
|
|
1747
1753
|
|
|
1748
1754
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
1749
1755
|
__proto__: null,
|
|
@@ -1755,6 +1761,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1755
1761
|
partialLossSubject: partialLossSubject,
|
|
1756
1762
|
partialProfitSubject: partialProfitSubject,
|
|
1757
1763
|
performanceEmitter: performanceEmitter,
|
|
1764
|
+
pingSubject: pingSubject,
|
|
1758
1765
|
progressBacktestEmitter: progressBacktestEmitter,
|
|
1759
1766
|
progressOptimizerEmitter: progressOptimizerEmitter,
|
|
1760
1767
|
progressWalkerEmitter: progressWalkerEmitter,
|
|
@@ -2243,6 +2250,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
|
|
|
2243
2250
|
exchangeName: self.params.method.context.exchangeName,
|
|
2244
2251
|
symbol: self.params.execution.context.symbol,
|
|
2245
2252
|
backtest: self.params.execution.context.backtest,
|
|
2253
|
+
reason: "timeout",
|
|
2246
2254
|
};
|
|
2247
2255
|
if (self.params.callbacks?.onTick) {
|
|
2248
2256
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2279,7 +2287,7 @@ const CHECK_SCHEDULED_SIGNAL_PRICE_ACTIVATION_FN = (scheduled, currentPrice) =>
|
|
|
2279
2287
|
return { shouldActivate, shouldCancel };
|
|
2280
2288
|
};
|
|
2281
2289
|
const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPrice) => {
|
|
2282
|
-
self.params.logger.info("ClientStrategy scheduled signal cancelled", {
|
|
2290
|
+
self.params.logger.info("ClientStrategy scheduled signal cancelled by StopLoss", {
|
|
2283
2291
|
symbol: self.params.execution.context.symbol,
|
|
2284
2292
|
signalId: scheduled.id,
|
|
2285
2293
|
position: scheduled.position,
|
|
@@ -2287,14 +2295,19 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
|
|
|
2287
2295
|
priceStopLoss: scheduled.priceStopLoss,
|
|
2288
2296
|
});
|
|
2289
2297
|
await self.setScheduledSignal(null);
|
|
2298
|
+
if (self.params.callbacks?.onCancel) {
|
|
2299
|
+
self.params.callbacks.onCancel(self.params.execution.context.symbol, scheduled, currentPrice, self.params.execution.context.backtest);
|
|
2300
|
+
}
|
|
2290
2301
|
const result = {
|
|
2291
|
-
action: "
|
|
2292
|
-
signal:
|
|
2302
|
+
action: "cancelled",
|
|
2303
|
+
signal: scheduled,
|
|
2304
|
+
currentPrice: currentPrice,
|
|
2305
|
+
closeTimestamp: self.params.execution.context.when.getTime(),
|
|
2293
2306
|
strategyName: self.params.method.context.strategyName,
|
|
2294
2307
|
exchangeName: self.params.method.context.exchangeName,
|
|
2295
2308
|
symbol: self.params.execution.context.symbol,
|
|
2296
|
-
currentPrice: currentPrice,
|
|
2297
2309
|
backtest: self.params.execution.context.backtest,
|
|
2310
|
+
reason: "price_reject",
|
|
2298
2311
|
};
|
|
2299
2312
|
if (self.params.callbacks?.onTick) {
|
|
2300
2313
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2369,7 +2382,16 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
2369
2382
|
}
|
|
2370
2383
|
return result;
|
|
2371
2384
|
};
|
|
2385
|
+
const CALL_PING_CALLBACKS_FN = async (self, scheduled, timestamp) => {
|
|
2386
|
+
// Call system onPing callback first (emits to pingSubject)
|
|
2387
|
+
await self.params.onPing(self.params.execution.context.symbol, self.params.method.context.strategyName, self.params.method.context.exchangeName, scheduled, self.params.execution.context.backtest, timestamp);
|
|
2388
|
+
// Call user onPing callback only if signal is still active (not cancelled, not activated)
|
|
2389
|
+
if (self.params.callbacks?.onPing) {
|
|
2390
|
+
await self.params.callbacks.onPing(self.params.execution.context.symbol, scheduled, new Date(timestamp), self.params.execution.context.backtest);
|
|
2391
|
+
}
|
|
2392
|
+
};
|
|
2372
2393
|
const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
|
|
2394
|
+
await CALL_PING_CALLBACKS_FN(self, scheduled, self.params.execution.context.when.getTime());
|
|
2373
2395
|
const result = {
|
|
2374
2396
|
action: "active",
|
|
2375
2397
|
signal: scheduled,
|
|
@@ -2597,13 +2619,14 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
|
|
|
2597
2619
|
}
|
|
2598
2620
|
return result;
|
|
2599
2621
|
};
|
|
2600
|
-
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp) => {
|
|
2622
|
+
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp, reason) => {
|
|
2601
2623
|
self.params.logger.info("ClientStrategy backtest scheduled signal cancelled", {
|
|
2602
2624
|
symbol: self.params.execution.context.symbol,
|
|
2603
2625
|
signalId: scheduled.id,
|
|
2604
2626
|
closeTimestamp,
|
|
2605
2627
|
averagePrice,
|
|
2606
2628
|
priceStopLoss: scheduled.priceStopLoss,
|
|
2629
|
+
reason,
|
|
2607
2630
|
});
|
|
2608
2631
|
await self.setScheduledSignal(null);
|
|
2609
2632
|
if (self.params.callbacks?.onCancel) {
|
|
@@ -2618,6 +2641,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
|
|
|
2618
2641
|
exchangeName: self.params.method.context.exchangeName,
|
|
2619
2642
|
symbol: self.params.execution.context.symbol,
|
|
2620
2643
|
backtest: self.params.execution.context.backtest,
|
|
2644
|
+
reason,
|
|
2621
2645
|
};
|
|
2622
2646
|
if (self.params.callbacks?.onTick) {
|
|
2623
2647
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2733,10 +2757,16 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2733
2757
|
}
|
|
2734
2758
|
const recentCandles = candles.slice(Math.max(0, i - (candlesCount - 1)), i + 1);
|
|
2735
2759
|
const averagePrice = GET_AVG_PRICE_FN(recentCandles);
|
|
2760
|
+
// КРИТИЧНО: Проверяем был ли сигнал отменен пользователем через cancel()
|
|
2761
|
+
if (self._cancelledSignal) {
|
|
2762
|
+
// Сигнал был отменен через cancel() в onPing
|
|
2763
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user");
|
|
2764
|
+
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2765
|
+
}
|
|
2736
2766
|
// КРИТИЧНО: Проверяем timeout ПЕРЕД проверкой цены
|
|
2737
2767
|
const elapsedTime = candle.timestamp - scheduled.scheduledAt;
|
|
2738
2768
|
if (elapsedTime >= maxTimeToWait) {
|
|
2739
|
-
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
|
|
2769
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "timeout");
|
|
2740
2770
|
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2741
2771
|
}
|
|
2742
2772
|
let shouldActivate = false;
|
|
@@ -2774,7 +2804,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2774
2804
|
}
|
|
2775
2805
|
}
|
|
2776
2806
|
if (shouldCancel) {
|
|
2777
|
-
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
|
|
2807
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "price_reject");
|
|
2778
2808
|
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2779
2809
|
}
|
|
2780
2810
|
if (shouldActivate) {
|
|
@@ -2786,6 +2816,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2786
2816
|
result: null,
|
|
2787
2817
|
};
|
|
2788
2818
|
}
|
|
2819
|
+
await CALL_PING_CALLBACKS_FN(self, scheduled, candle.timestamp);
|
|
2789
2820
|
}
|
|
2790
2821
|
return {
|
|
2791
2822
|
activated: false,
|
|
@@ -2939,8 +2970,9 @@ class ClientStrategy {
|
|
|
2939
2970
|
this.params = params;
|
|
2940
2971
|
this._isStopped = false;
|
|
2941
2972
|
this._pendingSignal = null;
|
|
2942
|
-
this._scheduledSignal = null;
|
|
2943
2973
|
this._lastSignalTimestamp = null;
|
|
2974
|
+
this._scheduledSignal = null;
|
|
2975
|
+
this._cancelledSignal = null;
|
|
2944
2976
|
/**
|
|
2945
2977
|
* Initializes strategy state by loading persisted signal from disk.
|
|
2946
2978
|
*
|
|
@@ -3007,6 +3039,18 @@ class ClientStrategy {
|
|
|
3007
3039
|
});
|
|
3008
3040
|
return this._pendingSignal;
|
|
3009
3041
|
}
|
|
3042
|
+
/**
|
|
3043
|
+
* Retrieves the current scheduled signal.
|
|
3044
|
+
* If no scheduled signal exists, returns null.
|
|
3045
|
+
* @returns Promise resolving to the scheduled signal or null.
|
|
3046
|
+
*/
|
|
3047
|
+
async getScheduledSignal(symbol, strategyName) {
|
|
3048
|
+
this.params.logger.debug("ClientStrategy getScheduledSignal", {
|
|
3049
|
+
symbol,
|
|
3050
|
+
strategyName,
|
|
3051
|
+
});
|
|
3052
|
+
return this._scheduledSignal;
|
|
3053
|
+
}
|
|
3010
3054
|
/**
|
|
3011
3055
|
* Returns the stopped state of the strategy.
|
|
3012
3056
|
*
|
|
@@ -3066,6 +3110,33 @@ class ClientStrategy {
|
|
|
3066
3110
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
3067
3111
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
3068
3112
|
}
|
|
3113
|
+
// Check if scheduled signal was cancelled - emit cancelled event once
|
|
3114
|
+
if (this._cancelledSignal) {
|
|
3115
|
+
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
3116
|
+
const cancelledSignal = this._cancelledSignal;
|
|
3117
|
+
this._cancelledSignal = null; // Clear after emitting
|
|
3118
|
+
this.params.logger.info("ClientStrategy tick: scheduled signal was cancelled", {
|
|
3119
|
+
symbol: this.params.execution.context.symbol,
|
|
3120
|
+
signalId: cancelledSignal.id,
|
|
3121
|
+
});
|
|
3122
|
+
// Call onCancel callback
|
|
3123
|
+
if (this.params.callbacks?.onCancel) {
|
|
3124
|
+
this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
|
|
3125
|
+
}
|
|
3126
|
+
const result = {
|
|
3127
|
+
action: "cancelled",
|
|
3128
|
+
signal: cancelledSignal,
|
|
3129
|
+
currentPrice,
|
|
3130
|
+
closeTimestamp: currentTime,
|
|
3131
|
+
strategyName: this.params.method.context.strategyName,
|
|
3132
|
+
exchangeName: this.params.method.context.exchangeName,
|
|
3133
|
+
symbol: this.params.execution.context.symbol,
|
|
3134
|
+
backtest: this.params.execution.context.backtest,
|
|
3135
|
+
reason: "user",
|
|
3136
|
+
cancelId: cancelledSignal.cancelId,
|
|
3137
|
+
};
|
|
3138
|
+
return result;
|
|
3139
|
+
}
|
|
3069
3140
|
// Monitor scheduled signal
|
|
3070
3141
|
if (this._scheduledSignal && !this._pendingSignal) {
|
|
3071
3142
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
@@ -3156,6 +3227,29 @@ class ClientStrategy {
|
|
|
3156
3227
|
if (!this.params.execution.context.backtest) {
|
|
3157
3228
|
throw new Error("ClientStrategy backtest: running in live context");
|
|
3158
3229
|
}
|
|
3230
|
+
// If signal was cancelled - return cancelled
|
|
3231
|
+
if (this._cancelledSignal) {
|
|
3232
|
+
this.params.logger.debug("ClientStrategy backtest: no signal (cancelled or not created)");
|
|
3233
|
+
const currentPrice = await this.params.exchange.getAveragePrice(symbol);
|
|
3234
|
+
const cancelledSignal = this._cancelledSignal;
|
|
3235
|
+
this._cancelledSignal = null; // Clear after using
|
|
3236
|
+
if (this.params.callbacks?.onCancel) {
|
|
3237
|
+
this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
|
|
3238
|
+
}
|
|
3239
|
+
const cancelledResult = {
|
|
3240
|
+
action: "cancelled",
|
|
3241
|
+
signal: cancelledSignal,
|
|
3242
|
+
currentPrice,
|
|
3243
|
+
closeTimestamp: this.params.execution.context.when.getTime(),
|
|
3244
|
+
strategyName: this.params.method.context.strategyName,
|
|
3245
|
+
exchangeName: this.params.method.context.exchangeName,
|
|
3246
|
+
symbol: this.params.execution.context.symbol,
|
|
3247
|
+
backtest: true,
|
|
3248
|
+
reason: "user",
|
|
3249
|
+
cancelId: cancelledSignal.cancelId,
|
|
3250
|
+
};
|
|
3251
|
+
return cancelledResult;
|
|
3252
|
+
}
|
|
3159
3253
|
if (!this._pendingSignal && !this._scheduledSignal) {
|
|
3160
3254
|
throw new Error("ClientStrategy backtest: no pending or scheduled signal");
|
|
3161
3255
|
}
|
|
@@ -3228,7 +3322,7 @@ class ClientStrategy {
|
|
|
3228
3322
|
maxMinutes: GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES,
|
|
3229
3323
|
reason: "timeout - price never reached priceOpen",
|
|
3230
3324
|
});
|
|
3231
|
-
return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp);
|
|
3325
|
+
return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp, "timeout");
|
|
3232
3326
|
}
|
|
3233
3327
|
}
|
|
3234
3328
|
// Process pending signal
|
|
@@ -3286,6 +3380,47 @@ class ClientStrategy {
|
|
|
3286
3380
|
}
|
|
3287
3381
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3288
3382
|
}
|
|
3383
|
+
/**
|
|
3384
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
3385
|
+
*
|
|
3386
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
3387
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
3388
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
3389
|
+
*
|
|
3390
|
+
* Use case: Cancel a scheduled entry that is no longer desired without stopping the entire strategy.
|
|
3391
|
+
*
|
|
3392
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3393
|
+
* @param strategyName - Name of the strategy
|
|
3394
|
+
* @param backtest - Whether running in backtest mode
|
|
3395
|
+
* @returns Promise that resolves when scheduled signal is cleared
|
|
3396
|
+
*
|
|
3397
|
+
* @example
|
|
3398
|
+
* ```typescript
|
|
3399
|
+
* // Cancel scheduled signal without stopping strategy
|
|
3400
|
+
* await strategy.cancel("BTCUSDT", "my-strategy", false);
|
|
3401
|
+
* // Strategy continues, can generate new signals
|
|
3402
|
+
* ```
|
|
3403
|
+
*/
|
|
3404
|
+
async cancel(symbol, strategyName, backtest, cancelId) {
|
|
3405
|
+
this.params.logger.debug("ClientStrategy cancel", {
|
|
3406
|
+
symbol,
|
|
3407
|
+
strategyName,
|
|
3408
|
+
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3409
|
+
backtest,
|
|
3410
|
+
cancelId,
|
|
3411
|
+
});
|
|
3412
|
+
// Save cancelled signal for next tick to emit cancelled event
|
|
3413
|
+
if (this._scheduledSignal) {
|
|
3414
|
+
this._cancelledSignal = Object.assign({}, this._scheduledSignal, {
|
|
3415
|
+
cancelId,
|
|
3416
|
+
});
|
|
3417
|
+
this._scheduledSignal = null;
|
|
3418
|
+
}
|
|
3419
|
+
if (backtest) {
|
|
3420
|
+
return;
|
|
3421
|
+
}
|
|
3422
|
+
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3423
|
+
}
|
|
3289
3424
|
}
|
|
3290
3425
|
|
|
3291
3426
|
const RISK_METHOD_NAME_GET_DATA = "RiskUtils.getData";
|
|
@@ -3612,6 +3747,27 @@ const GET_RISK_FN = (dto, backtest, self) => {
|
|
|
3612
3747
|
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
|
|
3613
3748
|
]);
|
|
3614
3749
|
};
|
|
3750
|
+
/**
|
|
3751
|
+
* Callback function for emitting ping events to pingSubject.
|
|
3752
|
+
*
|
|
3753
|
+
* Called by ClientStrategy when a scheduled signal is being monitored every minute.
|
|
3754
|
+
* Emits PingContract event to all subscribers.
|
|
3755
|
+
*
|
|
3756
|
+
* @param symbol - Trading pair symbol
|
|
3757
|
+
* @param strategyName - Strategy name that is monitoring this scheduled signal
|
|
3758
|
+
* @param exchangeName - Exchange name where this scheduled signal is being executed
|
|
3759
|
+
* @param data - Scheduled signal row data
|
|
3760
|
+
* @param backtest - True if backtest mode
|
|
3761
|
+
* @param timestamp - Event timestamp in milliseconds
|
|
3762
|
+
*/
|
|
3763
|
+
const COMMIT_PING_FN = async (symbol, strategyName, exchangeName, data, backtest, timestamp) => await pingSubject.next({
|
|
3764
|
+
symbol,
|
|
3765
|
+
strategyName,
|
|
3766
|
+
exchangeName,
|
|
3767
|
+
data,
|
|
3768
|
+
backtest,
|
|
3769
|
+
timestamp,
|
|
3770
|
+
});
|
|
3615
3771
|
/**
|
|
3616
3772
|
* Connection service routing strategy operations to correct ClientStrategy instance.
|
|
3617
3773
|
*
|
|
@@ -3669,6 +3825,7 @@ class StrategyConnectionService {
|
|
|
3669
3825
|
strategyName,
|
|
3670
3826
|
getSignal,
|
|
3671
3827
|
callbacks,
|
|
3828
|
+
onPing: COMMIT_PING_FN,
|
|
3672
3829
|
});
|
|
3673
3830
|
});
|
|
3674
3831
|
/**
|
|
@@ -3690,6 +3847,25 @@ class StrategyConnectionService {
|
|
|
3690
3847
|
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3691
3848
|
return await strategy.getPendingSignal(symbol, strategyName);
|
|
3692
3849
|
};
|
|
3850
|
+
/**
|
|
3851
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
3852
|
+
* If no scheduled signal exists, returns null.
|
|
3853
|
+
* Used internally for monitoring scheduled signal activation.
|
|
3854
|
+
*
|
|
3855
|
+
* @param symbol - Trading pair symbol
|
|
3856
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
3857
|
+
*
|
|
3858
|
+
* @returns Promise resolving to scheduled signal or null
|
|
3859
|
+
*/
|
|
3860
|
+
this.getScheduledSignal = async (backtest, symbol, strategyName) => {
|
|
3861
|
+
this.loggerService.log("strategyConnectionService getScheduledSignal", {
|
|
3862
|
+
symbol,
|
|
3863
|
+
strategyName,
|
|
3864
|
+
backtest,
|
|
3865
|
+
});
|
|
3866
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3867
|
+
return await strategy.getScheduledSignal(symbol, strategyName);
|
|
3868
|
+
};
|
|
3693
3869
|
/**
|
|
3694
3870
|
* Retrieves the stopped state of the strategy.
|
|
3695
3871
|
*
|
|
@@ -3805,6 +3981,28 @@ class StrategyConnectionService {
|
|
|
3805
3981
|
this.getStrategy.clear();
|
|
3806
3982
|
}
|
|
3807
3983
|
};
|
|
3984
|
+
/**
|
|
3985
|
+
* Cancels the scheduled signal for the specified strategy.
|
|
3986
|
+
*
|
|
3987
|
+
* Delegates to ClientStrategy.cancel() which clears the scheduled signal
|
|
3988
|
+
* without stopping the strategy or affecting pending signals.
|
|
3989
|
+
*
|
|
3990
|
+
* Note: Cancelled event will be emitted on next tick() call when strategy
|
|
3991
|
+
* detects the scheduled signal was cancelled.
|
|
3992
|
+
*
|
|
3993
|
+
* @param backtest - Whether running in backtest mode
|
|
3994
|
+
* @param ctx - Context with symbol and strategyName
|
|
3995
|
+
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
3996
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
3997
|
+
*/
|
|
3998
|
+
this.cancel = async (backtest, ctx, cancelId) => {
|
|
3999
|
+
this.loggerService.log("strategyConnectionService cancel", {
|
|
4000
|
+
ctx,
|
|
4001
|
+
cancelId,
|
|
4002
|
+
});
|
|
4003
|
+
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
|
|
4004
|
+
await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
|
|
4005
|
+
};
|
|
3808
4006
|
}
|
|
3809
4007
|
}
|
|
3810
4008
|
|
|
@@ -4750,6 +4948,26 @@ class StrategyCoreService {
|
|
|
4750
4948
|
await this.validate(symbol, strategyName);
|
|
4751
4949
|
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
|
|
4752
4950
|
};
|
|
4951
|
+
/**
|
|
4952
|
+
* Retrieves the currently active scheduled signal for the symbol.
|
|
4953
|
+
* If no scheduled signal exists, returns null.
|
|
4954
|
+
* Used internally for monitoring scheduled signal activation.
|
|
4955
|
+
*
|
|
4956
|
+
* @param symbol - Trading pair symbol
|
|
4957
|
+
* @param strategyName - Name of the strategy
|
|
4958
|
+
* @returns Promise resolving to scheduled signal or null
|
|
4959
|
+
*/
|
|
4960
|
+
this.getScheduledSignal = async (backtest, symbol, strategyName) => {
|
|
4961
|
+
this.loggerService.log("strategyCoreService getScheduledSignal", {
|
|
4962
|
+
symbol,
|
|
4963
|
+
strategyName,
|
|
4964
|
+
});
|
|
4965
|
+
if (!MethodContextService.hasContext()) {
|
|
4966
|
+
throw new Error("strategyCoreService getScheduledSignal requires a method context");
|
|
4967
|
+
}
|
|
4968
|
+
await this.validate(symbol, strategyName);
|
|
4969
|
+
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
|
|
4970
|
+
};
|
|
4753
4971
|
/**
|
|
4754
4972
|
* Checks if the strategy has been stopped.
|
|
4755
4973
|
*
|
|
@@ -4852,6 +5070,27 @@ class StrategyCoreService {
|
|
|
4852
5070
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
4853
5071
|
return await this.strategyConnectionService.stop(backtest, ctx);
|
|
4854
5072
|
};
|
|
5073
|
+
/**
|
|
5074
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
5075
|
+
*
|
|
5076
|
+
* Delegates to StrategyConnectionService.cancel() to clear scheduled signal
|
|
5077
|
+
* and emit cancelled event through emitters.
|
|
5078
|
+
* Does not require execution context.
|
|
5079
|
+
*
|
|
5080
|
+
* @param backtest - Whether running in backtest mode
|
|
5081
|
+
* @param ctx - Context with symbol and strategyName
|
|
5082
|
+
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
5083
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
5084
|
+
*/
|
|
5085
|
+
this.cancel = async (backtest, ctx, cancelId) => {
|
|
5086
|
+
this.loggerService.log("strategyCoreService cancel", {
|
|
5087
|
+
ctx,
|
|
5088
|
+
backtest,
|
|
5089
|
+
cancelId,
|
|
5090
|
+
});
|
|
5091
|
+
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5092
|
+
return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
|
|
5093
|
+
};
|
|
4855
5094
|
/**
|
|
4856
5095
|
* Clears the memoized ClientStrategy instance from cache.
|
|
4857
5096
|
*
|
|
@@ -7175,12 +7414,17 @@ const risk_columns = [
|
|
|
7175
7414
|
* - Signal identification (symbol, signal ID, position)
|
|
7176
7415
|
* - Price data (current price, entry price, take profit, stop loss)
|
|
7177
7416
|
* - Timing information (wait time in minutes before activation or cancellation)
|
|
7417
|
+
* - Cancellation details (reason: timeout/stoploss/user, optional user cancel ID)
|
|
7178
7418
|
*
|
|
7179
7419
|
* @remarks
|
|
7180
7420
|
* This configuration tracks the lifecycle of scheduled signals from creation to activation or cancellation.
|
|
7181
7421
|
* The "note" column visibility is controlled by {@link GLOBAL_CONFIG.CC_REPORT_SHOW_SIGNAL_NOTE}.
|
|
7182
7422
|
* Helps analyze signal scheduling effectiveness and cancellation patterns.
|
|
7183
7423
|
*
|
|
7424
|
+
* Cancellation tracking includes:
|
|
7425
|
+
* - cancelReason: "timeout" (expired wait time), "price_reject" (price hit SL), "user" (manual cancellation)
|
|
7426
|
+
* - cancelId: Optional ID provided when calling Backtest.cancel() or Live.cancel()
|
|
7427
|
+
*
|
|
7184
7428
|
* @example
|
|
7185
7429
|
* ```typescript
|
|
7186
7430
|
* import { schedule_columns } from "./assets/schedule.columns";
|
|
@@ -7189,9 +7433,9 @@ const risk_columns = [
|
|
|
7189
7433
|
* const service = new ScheduleMarkdownService();
|
|
7190
7434
|
* await service.getReport("BTCUSDT", "my-strategy", schedule_columns);
|
|
7191
7435
|
*
|
|
7192
|
-
* // Or customize for
|
|
7436
|
+
* // Or customize for cancellation analysis
|
|
7193
7437
|
* const customColumns = schedule_columns.filter(col =>
|
|
7194
|
-
* ["timestamp", "action", "
|
|
7438
|
+
* ["timestamp", "action", "cancelReason", "cancelId"].includes(col.key)
|
|
7195
7439
|
* );
|
|
7196
7440
|
* await service.getReport("BTCUSDT", "my-strategy", customColumns);
|
|
7197
7441
|
* ```
|
|
@@ -7240,7 +7484,7 @@ const schedule_columns = [
|
|
|
7240
7484
|
{
|
|
7241
7485
|
key: "currentPrice",
|
|
7242
7486
|
label: "Current Price",
|
|
7243
|
-
format: (data) => `${data.currentPrice.toFixed(8)} USD
|
|
7487
|
+
format: (data) => data.currentPrice ? `${data.currentPrice.toFixed(8)} USD` : "N/A",
|
|
7244
7488
|
isVisible: () => true,
|
|
7245
7489
|
},
|
|
7246
7490
|
{
|
|
@@ -7267,6 +7511,18 @@ const schedule_columns = [
|
|
|
7267
7511
|
format: (data) => data.duration !== undefined ? `${data.duration}` : "N/A",
|
|
7268
7512
|
isVisible: () => true,
|
|
7269
7513
|
},
|
|
7514
|
+
{
|
|
7515
|
+
key: "cancelReason",
|
|
7516
|
+
label: "Cancel Reason",
|
|
7517
|
+
format: (data) => data.cancelReason ? data.cancelReason.toUpperCase() : "N/A",
|
|
7518
|
+
isVisible: () => true,
|
|
7519
|
+
},
|
|
7520
|
+
{
|
|
7521
|
+
key: "cancelId",
|
|
7522
|
+
label: "Cancel ID",
|
|
7523
|
+
format: (data) => data.cancelId ?? "N/A",
|
|
7524
|
+
isVisible: () => true,
|
|
7525
|
+
},
|
|
7270
7526
|
];
|
|
7271
7527
|
|
|
7272
7528
|
/**
|
|
@@ -8447,6 +8703,8 @@ let ReportStorage$3 = class ReportStorage {
|
|
|
8447
8703
|
stopLoss: data.signal.priceStopLoss,
|
|
8448
8704
|
closeTimestamp: data.closeTimestamp,
|
|
8449
8705
|
duration: durationMin,
|
|
8706
|
+
cancelReason: data.reason,
|
|
8707
|
+
cancelId: data.cancelId,
|
|
8450
8708
|
};
|
|
8451
8709
|
this._eventList.unshift(newEvent);
|
|
8452
8710
|
// Trim queue if exceeded MAX_EVENTS
|
|
@@ -14727,6 +14985,8 @@ const LISTEN_PARTIAL_LOSS_METHOD_NAME = "event.listenPartialLoss";
|
|
|
14727
14985
|
const LISTEN_PARTIAL_LOSS_ONCE_METHOD_NAME = "event.listenPartialLossOnce";
|
|
14728
14986
|
const LISTEN_RISK_METHOD_NAME = "event.listenRisk";
|
|
14729
14987
|
const LISTEN_RISK_ONCE_METHOD_NAME = "event.listenRiskOnce";
|
|
14988
|
+
const LISTEN_PING_METHOD_NAME = "event.listenPing";
|
|
14989
|
+
const LISTEN_PING_ONCE_METHOD_NAME = "event.listenPingOnce";
|
|
14730
14990
|
/**
|
|
14731
14991
|
* Subscribes to all signal events with queued async processing.
|
|
14732
14992
|
*
|
|
@@ -15594,6 +15854,67 @@ function listenRiskOnce(filterFn, fn) {
|
|
|
15594
15854
|
backtest$1.loggerService.log(LISTEN_RISK_ONCE_METHOD_NAME);
|
|
15595
15855
|
return riskSubject.filter(filterFn).once(fn);
|
|
15596
15856
|
}
|
|
15857
|
+
/**
|
|
15858
|
+
* Subscribes to ping events during scheduled signal monitoring with queued async processing.
|
|
15859
|
+
*
|
|
15860
|
+
* Events are emitted every minute when a scheduled signal is being monitored (waiting for activation).
|
|
15861
|
+
* Allows tracking of scheduled signal lifecycle and custom monitoring logic.
|
|
15862
|
+
*
|
|
15863
|
+
* @param fn - Callback function to handle ping events
|
|
15864
|
+
* @returns Unsubscribe function to stop listening
|
|
15865
|
+
*
|
|
15866
|
+
* @example
|
|
15867
|
+
* ```typescript
|
|
15868
|
+
* import { listenPing } from "./function/event";
|
|
15869
|
+
*
|
|
15870
|
+
* const unsubscribe = listenPing((event) => {
|
|
15871
|
+
* console.log(`Ping for ${event.symbol} at ${new Date(event.timestamp).toISOString()}`);
|
|
15872
|
+
* console.log(`Strategy: ${event.strategyName}, Exchange: ${event.exchangeName}`);
|
|
15873
|
+
* console.log(`Mode: ${event.backtest ? "Backtest" : "Live"}`);
|
|
15874
|
+
* });
|
|
15875
|
+
*
|
|
15876
|
+
* // Later: stop listening
|
|
15877
|
+
* unsubscribe();
|
|
15878
|
+
* ```
|
|
15879
|
+
*/
|
|
15880
|
+
function listenPing(fn) {
|
|
15881
|
+
backtest$1.loggerService.log(LISTEN_PING_METHOD_NAME);
|
|
15882
|
+
return pingSubject.subscribe(queued(async (event) => fn(event)));
|
|
15883
|
+
}
|
|
15884
|
+
/**
|
|
15885
|
+
* Subscribes to filtered ping events with one-time execution.
|
|
15886
|
+
*
|
|
15887
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
15888
|
+
* and automatically unsubscribes. Useful for waiting for specific ping conditions.
|
|
15889
|
+
*
|
|
15890
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
15891
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
15892
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
15893
|
+
*
|
|
15894
|
+
* @example
|
|
15895
|
+
* ```typescript
|
|
15896
|
+
* import { listenPingOnce } from "./function/event";
|
|
15897
|
+
*
|
|
15898
|
+
* // Wait for first ping on BTCUSDT
|
|
15899
|
+
* listenPingOnce(
|
|
15900
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
15901
|
+
* (event) => console.log("First BTCUSDT ping received")
|
|
15902
|
+
* );
|
|
15903
|
+
*
|
|
15904
|
+
* // Wait for ping in backtest mode
|
|
15905
|
+
* const cancel = listenPingOnce(
|
|
15906
|
+
* (event) => event.backtest === true,
|
|
15907
|
+
* (event) => console.log("Backtest ping received at", new Date(event.timestamp))
|
|
15908
|
+
* );
|
|
15909
|
+
*
|
|
15910
|
+
* // Cancel if needed before event fires
|
|
15911
|
+
* cancel();
|
|
15912
|
+
* ```
|
|
15913
|
+
*/
|
|
15914
|
+
function listenPingOnce(filterFn, fn) {
|
|
15915
|
+
backtest$1.loggerService.log(LISTEN_PING_ONCE_METHOD_NAME);
|
|
15916
|
+
return pingSubject.filter(filterFn).once(fn);
|
|
15917
|
+
}
|
|
15597
15918
|
|
|
15598
15919
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
15599
15920
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
@@ -15867,6 +16188,8 @@ const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
|
|
|
15867
16188
|
const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
|
|
15868
16189
|
const BACKTEST_METHOD_NAME_TASK = "BacktestUtils.task";
|
|
15869
16190
|
const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
|
|
16191
|
+
const BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL = "BacktestUtils.getPendingSignal";
|
|
16192
|
+
const BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL = "BacktestUtils.getScheduledSignal";
|
|
15870
16193
|
/**
|
|
15871
16194
|
* Internal task function that runs backtest and handles completion.
|
|
15872
16195
|
* Consumes backtest results and updates instance state flags.
|
|
@@ -16057,6 +16380,54 @@ class BacktestInstance {
|
|
|
16057
16380
|
this._isStopped = true;
|
|
16058
16381
|
};
|
|
16059
16382
|
};
|
|
16383
|
+
/**
|
|
16384
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
16385
|
+
* If no active signal exists, returns null.
|
|
16386
|
+
*
|
|
16387
|
+
* @param symbol - Trading pair symbol
|
|
16388
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
16389
|
+
* @returns Promise resolving to pending signal or null
|
|
16390
|
+
*
|
|
16391
|
+
* @example
|
|
16392
|
+
* ```typescript
|
|
16393
|
+
* const instance = new BacktestInstance();
|
|
16394
|
+
* const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
|
|
16395
|
+
* if (pending) {
|
|
16396
|
+
* console.log("Active signal:", pending.id);
|
|
16397
|
+
* }
|
|
16398
|
+
* ```
|
|
16399
|
+
*/
|
|
16400
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
16401
|
+
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL, {
|
|
16402
|
+
symbol,
|
|
16403
|
+
strategyName,
|
|
16404
|
+
});
|
|
16405
|
+
return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
|
|
16406
|
+
};
|
|
16407
|
+
/**
|
|
16408
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
16409
|
+
* If no scheduled signal exists, returns null.
|
|
16410
|
+
*
|
|
16411
|
+
* @param symbol - Trading pair symbol
|
|
16412
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
16413
|
+
* @returns Promise resolving to scheduled signal or null
|
|
16414
|
+
*
|
|
16415
|
+
* @example
|
|
16416
|
+
* ```typescript
|
|
16417
|
+
* const instance = new BacktestInstance();
|
|
16418
|
+
* const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
16419
|
+
* if (scheduled) {
|
|
16420
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
16421
|
+
* }
|
|
16422
|
+
* ```
|
|
16423
|
+
*/
|
|
16424
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
16425
|
+
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
|
|
16426
|
+
symbol,
|
|
16427
|
+
strategyName,
|
|
16428
|
+
});
|
|
16429
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
|
|
16430
|
+
};
|
|
16060
16431
|
/**
|
|
16061
16432
|
* Stops the strategy from generating new signals.
|
|
16062
16433
|
*
|
|
@@ -16081,6 +16452,32 @@ class BacktestInstance {
|
|
|
16081
16452
|
});
|
|
16082
16453
|
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16083
16454
|
};
|
|
16455
|
+
/**
|
|
16456
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
16457
|
+
*
|
|
16458
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
16459
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
16460
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
16461
|
+
*
|
|
16462
|
+
* @param symbol - Trading pair symbol
|
|
16463
|
+
* @param strategyName - Strategy name
|
|
16464
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
16465
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
16466
|
+
*
|
|
16467
|
+
* @example
|
|
16468
|
+
* ```typescript
|
|
16469
|
+
* const instance = new BacktestInstance();
|
|
16470
|
+
* await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
16471
|
+
* ```
|
|
16472
|
+
*/
|
|
16473
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
16474
|
+
backtest$1.loggerService.info("BacktestInstance.cancel", {
|
|
16475
|
+
symbol,
|
|
16476
|
+
strategyName,
|
|
16477
|
+
cancelId,
|
|
16478
|
+
});
|
|
16479
|
+
await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
|
|
16480
|
+
};
|
|
16084
16481
|
/**
|
|
16085
16482
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
16086
16483
|
*
|
|
@@ -16232,6 +16629,58 @@ class BacktestUtils {
|
|
|
16232
16629
|
const instance = this._getInstance(symbol, context.strategyName);
|
|
16233
16630
|
return instance.background(symbol, context);
|
|
16234
16631
|
};
|
|
16632
|
+
/**
|
|
16633
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
16634
|
+
* If no active signal exists, returns null.
|
|
16635
|
+
*
|
|
16636
|
+
* @param symbol - Trading pair symbol
|
|
16637
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
16638
|
+
* @returns Promise resolving to pending signal or null
|
|
16639
|
+
*
|
|
16640
|
+
* @example
|
|
16641
|
+
* ```typescript
|
|
16642
|
+
* const pending = await Backtest.getPendingSignal("BTCUSDT", "my-strategy");
|
|
16643
|
+
* if (pending) {
|
|
16644
|
+
* console.log("Active signal:", pending.id);
|
|
16645
|
+
* }
|
|
16646
|
+
* ```
|
|
16647
|
+
*/
|
|
16648
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
16649
|
+
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16650
|
+
{
|
|
16651
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16652
|
+
riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16653
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
16654
|
+
}
|
|
16655
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16656
|
+
return await instance.getPendingSignal(symbol, strategyName);
|
|
16657
|
+
};
|
|
16658
|
+
/**
|
|
16659
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
16660
|
+
* If no scheduled signal exists, returns null.
|
|
16661
|
+
*
|
|
16662
|
+
* @param symbol - Trading pair symbol
|
|
16663
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
16664
|
+
* @returns Promise resolving to scheduled signal or null
|
|
16665
|
+
*
|
|
16666
|
+
* @example
|
|
16667
|
+
* ```typescript
|
|
16668
|
+
* const scheduled = await Backtest.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
16669
|
+
* if (scheduled) {
|
|
16670
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
16671
|
+
* }
|
|
16672
|
+
* ```
|
|
16673
|
+
*/
|
|
16674
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
16675
|
+
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16676
|
+
{
|
|
16677
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16678
|
+
riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16679
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
16680
|
+
}
|
|
16681
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16682
|
+
return await instance.getScheduledSignal(symbol, strategyName);
|
|
16683
|
+
};
|
|
16235
16684
|
/**
|
|
16236
16685
|
* Stops the strategy from generating new signals.
|
|
16237
16686
|
*
|
|
@@ -16259,6 +16708,34 @@ class BacktestUtils {
|
|
|
16259
16708
|
const instance = this._getInstance(symbol, strategyName);
|
|
16260
16709
|
return await instance.stop(symbol, strategyName);
|
|
16261
16710
|
};
|
|
16711
|
+
/**
|
|
16712
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
16713
|
+
*
|
|
16714
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
16715
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
16716
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
16717
|
+
*
|
|
16718
|
+
* @param symbol - Trading pair symbol
|
|
16719
|
+
* @param strategyName - Strategy name
|
|
16720
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
16721
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
16722
|
+
*
|
|
16723
|
+
* @example
|
|
16724
|
+
* ```typescript
|
|
16725
|
+
* // Cancel scheduled signal with custom ID
|
|
16726
|
+
* await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
16727
|
+
* ```
|
|
16728
|
+
*/
|
|
16729
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
16730
|
+
backtest$1.strategyValidationService.validate(strategyName, "BacktestUtils.cancel");
|
|
16731
|
+
{
|
|
16732
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16733
|
+
riskName && backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel");
|
|
16734
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel"));
|
|
16735
|
+
}
|
|
16736
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16737
|
+
return await instance.cancel(symbol, strategyName, cancelId);
|
|
16738
|
+
};
|
|
16262
16739
|
/**
|
|
16263
16740
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
16264
16741
|
*
|
|
@@ -16380,6 +16857,9 @@ const LIVE_METHOD_NAME_GET_DATA = "LiveUtils.getData";
|
|
|
16380
16857
|
const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
|
|
16381
16858
|
const LIVE_METHOD_NAME_TASK = "LiveUtils.task";
|
|
16382
16859
|
const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
|
|
16860
|
+
const LIVE_METHOD_NAME_GET_PENDING_SIGNAL = "LiveUtils.getPendingSignal";
|
|
16861
|
+
const LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL = "LiveUtils.getScheduledSignal";
|
|
16862
|
+
const LIVE_METHOD_NAME_CANCEL = "LiveUtils.cancel";
|
|
16383
16863
|
/**
|
|
16384
16864
|
* Internal task function that runs live trading and handles completion.
|
|
16385
16865
|
* Consumes live trading results and updates instance state flags.
|
|
@@ -16574,6 +17054,54 @@ class LiveInstance {
|
|
|
16574
17054
|
this._isStopped = true;
|
|
16575
17055
|
};
|
|
16576
17056
|
};
|
|
17057
|
+
/**
|
|
17058
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
17059
|
+
* If no active signal exists, returns null.
|
|
17060
|
+
*
|
|
17061
|
+
* @param symbol - Trading pair symbol
|
|
17062
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
17063
|
+
* @returns Promise resolving to pending signal or null
|
|
17064
|
+
*
|
|
17065
|
+
* @example
|
|
17066
|
+
* ```typescript
|
|
17067
|
+
* const instance = new LiveInstance();
|
|
17068
|
+
* const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
|
|
17069
|
+
* if (pending) {
|
|
17070
|
+
* console.log("Active signal:", pending.id);
|
|
17071
|
+
* }
|
|
17072
|
+
* ```
|
|
17073
|
+
*/
|
|
17074
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
17075
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_PENDING_SIGNAL, {
|
|
17076
|
+
symbol,
|
|
17077
|
+
strategyName,
|
|
17078
|
+
});
|
|
17079
|
+
return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
|
|
17080
|
+
};
|
|
17081
|
+
/**
|
|
17082
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
17083
|
+
* If no scheduled signal exists, returns null.
|
|
17084
|
+
*
|
|
17085
|
+
* @param symbol - Trading pair symbol
|
|
17086
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
17087
|
+
* @returns Promise resolving to scheduled signal or null
|
|
17088
|
+
*
|
|
17089
|
+
* @example
|
|
17090
|
+
* ```typescript
|
|
17091
|
+
* const instance = new LiveInstance();
|
|
17092
|
+
* const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
17093
|
+
* if (scheduled) {
|
|
17094
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
17095
|
+
* }
|
|
17096
|
+
* ```
|
|
17097
|
+
*/
|
|
17098
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
17099
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
|
|
17100
|
+
symbol,
|
|
17101
|
+
strategyName,
|
|
17102
|
+
});
|
|
17103
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
|
|
17104
|
+
};
|
|
16577
17105
|
/**
|
|
16578
17106
|
* Stops the strategy from generating new signals.
|
|
16579
17107
|
*
|
|
@@ -16598,6 +17126,32 @@ class LiveInstance {
|
|
|
16598
17126
|
});
|
|
16599
17127
|
await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
|
|
16600
17128
|
};
|
|
17129
|
+
/**
|
|
17130
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
17131
|
+
*
|
|
17132
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
17133
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
17134
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
17135
|
+
*
|
|
17136
|
+
* @param symbol - Trading pair symbol
|
|
17137
|
+
* @param strategyName - Strategy name
|
|
17138
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
17139
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
17140
|
+
*
|
|
17141
|
+
* @example
|
|
17142
|
+
* ```typescript
|
|
17143
|
+
* const instance = new LiveInstance();
|
|
17144
|
+
* await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
17145
|
+
* ```
|
|
17146
|
+
*/
|
|
17147
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
17148
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_CANCEL, {
|
|
17149
|
+
symbol,
|
|
17150
|
+
strategyName,
|
|
17151
|
+
cancelId,
|
|
17152
|
+
});
|
|
17153
|
+
await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
|
|
17154
|
+
};
|
|
16601
17155
|
/**
|
|
16602
17156
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
16603
17157
|
*
|
|
@@ -16760,6 +17314,58 @@ class LiveUtils {
|
|
|
16760
17314
|
const instance = this._getInstance(symbol, context.strategyName);
|
|
16761
17315
|
return instance.background(symbol, context);
|
|
16762
17316
|
};
|
|
17317
|
+
/**
|
|
17318
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
17319
|
+
* If no active signal exists, returns null.
|
|
17320
|
+
*
|
|
17321
|
+
* @param symbol - Trading pair symbol
|
|
17322
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
17323
|
+
* @returns Promise resolving to pending signal or null
|
|
17324
|
+
*
|
|
17325
|
+
* @example
|
|
17326
|
+
* ```typescript
|
|
17327
|
+
* const pending = await Live.getPendingSignal("BTCUSDT", "my-strategy");
|
|
17328
|
+
* if (pending) {
|
|
17329
|
+
* console.log("Active signal:", pending.id);
|
|
17330
|
+
* }
|
|
17331
|
+
* ```
|
|
17332
|
+
*/
|
|
17333
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
17334
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17335
|
+
{
|
|
17336
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17337
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17338
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
17339
|
+
}
|
|
17340
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17341
|
+
return await instance.getPendingSignal(symbol, strategyName);
|
|
17342
|
+
};
|
|
17343
|
+
/**
|
|
17344
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
17345
|
+
* If no scheduled signal exists, returns null.
|
|
17346
|
+
*
|
|
17347
|
+
* @param symbol - Trading pair symbol
|
|
17348
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
17349
|
+
* @returns Promise resolving to scheduled signal or null
|
|
17350
|
+
*
|
|
17351
|
+
* @example
|
|
17352
|
+
* ```typescript
|
|
17353
|
+
* const scheduled = await Live.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
17354
|
+
* if (scheduled) {
|
|
17355
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
17356
|
+
* }
|
|
17357
|
+
* ```
|
|
17358
|
+
*/
|
|
17359
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
17360
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17361
|
+
{
|
|
17362
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17363
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17364
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
17365
|
+
}
|
|
17366
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17367
|
+
return await instance.getScheduledSignal(symbol, strategyName);
|
|
17368
|
+
};
|
|
16763
17369
|
/**
|
|
16764
17370
|
* Stops the strategy from generating new signals.
|
|
16765
17371
|
*
|
|
@@ -16787,6 +17393,34 @@ class LiveUtils {
|
|
|
16787
17393
|
const instance = this._getInstance(symbol, strategyName);
|
|
16788
17394
|
return await instance.stop(symbol, strategyName);
|
|
16789
17395
|
};
|
|
17396
|
+
/**
|
|
17397
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
17398
|
+
*
|
|
17399
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
17400
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
17401
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
17402
|
+
*
|
|
17403
|
+
* @param symbol - Trading pair symbol
|
|
17404
|
+
* @param strategyName - Strategy name
|
|
17405
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
17406
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
17407
|
+
*
|
|
17408
|
+
* @example
|
|
17409
|
+
* ```typescript
|
|
17410
|
+
* // Cancel scheduled signal in live trading with custom ID
|
|
17411
|
+
* await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
17412
|
+
* ```
|
|
17413
|
+
*/
|
|
17414
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
17415
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
|
|
17416
|
+
{
|
|
17417
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17418
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
|
|
17419
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
|
|
17420
|
+
}
|
|
17421
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17422
|
+
return await instance.cancel(symbol, strategyName, cancelId);
|
|
17423
|
+
};
|
|
16790
17424
|
/**
|
|
16791
17425
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
16792
17426
|
*
|
|
@@ -18947,4 +19581,4 @@ class CacheUtils {
|
|
|
18947
19581
|
*/
|
|
18948
19582
|
const Cache = new CacheUtils();
|
|
18949
19583
|
|
|
18950
|
-
export { Backtest, Cache, Constant, Exchange, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Risk, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getColumns, getConfig, getDate, getDefaultColumns, getDefaultConfig, getMode, hasTradeContext, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenRisk, listenRiskOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setColumns, setConfig, setLogger, validate };
|
|
19584
|
+
export { Backtest, Cache, Constant, Exchange, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Risk, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getColumns, getConfig, getDate, getDefaultColumns, getDefaultConfig, getMode, hasTradeContext, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenPing, listenPingOnce, listenRisk, listenRiskOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setColumns, setConfig, setLogger, validate };
|