backtest-kit 1.5.47 → 1.6.2
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 +660 -13
- package/build/index.mjs +659 -14
- package/package.json +1 -1
- package/types.d.ts +322 -2
package/build/index.cjs
CHANGED
|
@@ -1746,6 +1746,12 @@ const partialLossSubject = new functoolsKit.Subject();
|
|
|
1746
1746
|
* Does not emit for allowed signals (prevents spam).
|
|
1747
1747
|
*/
|
|
1748
1748
|
const riskSubject = new functoolsKit.Subject();
|
|
1749
|
+
/**
|
|
1750
|
+
* Ping emitter for scheduled signal monitoring events.
|
|
1751
|
+
* Emits every minute when a scheduled signal is being monitored (waiting for activation).
|
|
1752
|
+
* Allows users to track scheduled signal lifecycle and implement custom cancellation logic.
|
|
1753
|
+
*/
|
|
1754
|
+
const pingSubject = new functoolsKit.Subject();
|
|
1749
1755
|
|
|
1750
1756
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
1751
1757
|
__proto__: null,
|
|
@@ -1757,6 +1763,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
1757
1763
|
partialLossSubject: partialLossSubject,
|
|
1758
1764
|
partialProfitSubject: partialProfitSubject,
|
|
1759
1765
|
performanceEmitter: performanceEmitter,
|
|
1766
|
+
pingSubject: pingSubject,
|
|
1760
1767
|
progressBacktestEmitter: progressBacktestEmitter,
|
|
1761
1768
|
progressOptimizerEmitter: progressOptimizerEmitter,
|
|
1762
1769
|
progressWalkerEmitter: progressWalkerEmitter,
|
|
@@ -2160,7 +2167,7 @@ const GET_SIGNAL_FN = functoolsKit.trycatch(async (self) => {
|
|
|
2160
2167
|
}, {
|
|
2161
2168
|
defaultValue: null,
|
|
2162
2169
|
fallback: (error) => {
|
|
2163
|
-
const message = "ClientStrategy
|
|
2170
|
+
const message = "ClientStrategy GET_SIGNAL_FN thrown";
|
|
2164
2171
|
const payload = {
|
|
2165
2172
|
error: functoolsKit.errorData(error),
|
|
2166
2173
|
message: functoolsKit.getErrorMessage(error),
|
|
@@ -2245,6 +2252,7 @@ const CHECK_SCHEDULED_SIGNAL_TIMEOUT_FN = async (self, scheduled, currentPrice)
|
|
|
2245
2252
|
exchangeName: self.params.method.context.exchangeName,
|
|
2246
2253
|
symbol: self.params.execution.context.symbol,
|
|
2247
2254
|
backtest: self.params.execution.context.backtest,
|
|
2255
|
+
reason: "timeout",
|
|
2248
2256
|
};
|
|
2249
2257
|
if (self.params.callbacks?.onTick) {
|
|
2250
2258
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2281,7 +2289,7 @@ const CHECK_SCHEDULED_SIGNAL_PRICE_ACTIVATION_FN = (scheduled, currentPrice) =>
|
|
|
2281
2289
|
return { shouldActivate, shouldCancel };
|
|
2282
2290
|
};
|
|
2283
2291
|
const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPrice) => {
|
|
2284
|
-
self.params.logger.info("ClientStrategy scheduled signal cancelled", {
|
|
2292
|
+
self.params.logger.info("ClientStrategy scheduled signal cancelled by StopLoss", {
|
|
2285
2293
|
symbol: self.params.execution.context.symbol,
|
|
2286
2294
|
signalId: scheduled.id,
|
|
2287
2295
|
position: scheduled.position,
|
|
@@ -2289,14 +2297,19 @@ const CANCEL_SCHEDULED_SIGNAL_BY_STOPLOSS_FN = async (self, scheduled, currentPr
|
|
|
2289
2297
|
priceStopLoss: scheduled.priceStopLoss,
|
|
2290
2298
|
});
|
|
2291
2299
|
await self.setScheduledSignal(null);
|
|
2300
|
+
if (self.params.callbacks?.onCancel) {
|
|
2301
|
+
self.params.callbacks.onCancel(self.params.execution.context.symbol, scheduled, currentPrice, self.params.execution.context.backtest);
|
|
2302
|
+
}
|
|
2292
2303
|
const result = {
|
|
2293
|
-
action: "
|
|
2294
|
-
signal:
|
|
2304
|
+
action: "cancelled",
|
|
2305
|
+
signal: scheduled,
|
|
2306
|
+
currentPrice: currentPrice,
|
|
2307
|
+
closeTimestamp: self.params.execution.context.when.getTime(),
|
|
2295
2308
|
strategyName: self.params.method.context.strategyName,
|
|
2296
2309
|
exchangeName: self.params.method.context.exchangeName,
|
|
2297
2310
|
symbol: self.params.execution.context.symbol,
|
|
2298
|
-
currentPrice: currentPrice,
|
|
2299
2311
|
backtest: self.params.execution.context.backtest,
|
|
2312
|
+
reason: "price_reject",
|
|
2300
2313
|
};
|
|
2301
2314
|
if (self.params.callbacks?.onTick) {
|
|
2302
2315
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2371,7 +2384,27 @@ const ACTIVATE_SCHEDULED_SIGNAL_FN = async (self, scheduled, activationTimestamp
|
|
|
2371
2384
|
}
|
|
2372
2385
|
return result;
|
|
2373
2386
|
};
|
|
2387
|
+
const CALL_PING_CALLBACKS_FN = functoolsKit.trycatch(async (self, scheduled, timestamp) => {
|
|
2388
|
+
// Call system onPing callback first (emits to pingSubject)
|
|
2389
|
+
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);
|
|
2390
|
+
// Call user onPing callback only if signal is still active (not cancelled, not activated)
|
|
2391
|
+
if (self.params.callbacks?.onPing) {
|
|
2392
|
+
await self.params.callbacks.onPing(self.params.execution.context.symbol, scheduled, new Date(timestamp), self.params.execution.context.backtest);
|
|
2393
|
+
}
|
|
2394
|
+
}, {
|
|
2395
|
+
fallback: (error) => {
|
|
2396
|
+
const message = "ClientStrategy CALL_PING_CALLBACKS_FN thrown";
|
|
2397
|
+
const payload = {
|
|
2398
|
+
error: functoolsKit.errorData(error),
|
|
2399
|
+
message: functoolsKit.getErrorMessage(error),
|
|
2400
|
+
};
|
|
2401
|
+
backtest$1.loggerService.warn(message, payload);
|
|
2402
|
+
console.warn(message, payload);
|
|
2403
|
+
errorEmitter.next(error);
|
|
2404
|
+
}
|
|
2405
|
+
});
|
|
2374
2406
|
const RETURN_SCHEDULED_SIGNAL_ACTIVE_FN = async (self, scheduled, currentPrice) => {
|
|
2407
|
+
await CALL_PING_CALLBACKS_FN(self, scheduled, self.params.execution.context.when.getTime());
|
|
2375
2408
|
const result = {
|
|
2376
2409
|
action: "active",
|
|
2377
2410
|
signal: scheduled,
|
|
@@ -2599,13 +2632,14 @@ const RETURN_IDLE_FN = async (self, currentPrice) => {
|
|
|
2599
2632
|
}
|
|
2600
2633
|
return result;
|
|
2601
2634
|
};
|
|
2602
|
-
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp) => {
|
|
2635
|
+
const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePrice, closeTimestamp, reason) => {
|
|
2603
2636
|
self.params.logger.info("ClientStrategy backtest scheduled signal cancelled", {
|
|
2604
2637
|
symbol: self.params.execution.context.symbol,
|
|
2605
2638
|
signalId: scheduled.id,
|
|
2606
2639
|
closeTimestamp,
|
|
2607
2640
|
averagePrice,
|
|
2608
2641
|
priceStopLoss: scheduled.priceStopLoss,
|
|
2642
|
+
reason,
|
|
2609
2643
|
});
|
|
2610
2644
|
await self.setScheduledSignal(null);
|
|
2611
2645
|
if (self.params.callbacks?.onCancel) {
|
|
@@ -2620,6 +2654,7 @@ const CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN = async (self, scheduled, averagePr
|
|
|
2620
2654
|
exchangeName: self.params.method.context.exchangeName,
|
|
2621
2655
|
symbol: self.params.execution.context.symbol,
|
|
2622
2656
|
backtest: self.params.execution.context.backtest,
|
|
2657
|
+
reason,
|
|
2623
2658
|
};
|
|
2624
2659
|
if (self.params.callbacks?.onTick) {
|
|
2625
2660
|
self.params.callbacks.onTick(self.params.execution.context.symbol, result, self.params.execution.context.backtest);
|
|
@@ -2735,10 +2770,16 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2735
2770
|
}
|
|
2736
2771
|
const recentCandles = candles.slice(Math.max(0, i - (candlesCount - 1)), i + 1);
|
|
2737
2772
|
const averagePrice = GET_AVG_PRICE_FN(recentCandles);
|
|
2773
|
+
// КРИТИЧНО: Проверяем был ли сигнал отменен пользователем через cancel()
|
|
2774
|
+
if (self._cancelledSignal) {
|
|
2775
|
+
// Сигнал был отменен через cancel() в onPing
|
|
2776
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "user");
|
|
2777
|
+
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2778
|
+
}
|
|
2738
2779
|
// КРИТИЧНО: Проверяем timeout ПЕРЕД проверкой цены
|
|
2739
2780
|
const elapsedTime = candle.timestamp - scheduled.scheduledAt;
|
|
2740
2781
|
if (elapsedTime >= maxTimeToWait) {
|
|
2741
|
-
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
|
|
2782
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "timeout");
|
|
2742
2783
|
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2743
2784
|
}
|
|
2744
2785
|
let shouldActivate = false;
|
|
@@ -2776,7 +2817,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2776
2817
|
}
|
|
2777
2818
|
}
|
|
2778
2819
|
if (shouldCancel) {
|
|
2779
|
-
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp);
|
|
2820
|
+
const result = await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(self, scheduled, averagePrice, candle.timestamp, "price_reject");
|
|
2780
2821
|
return { activated: false, cancelled: true, activationIndex: i, result };
|
|
2781
2822
|
}
|
|
2782
2823
|
if (shouldActivate) {
|
|
@@ -2788,6 +2829,7 @@ const PROCESS_SCHEDULED_SIGNAL_CANDLES_FN = async (self, scheduled, candles) =>
|
|
|
2788
2829
|
result: null,
|
|
2789
2830
|
};
|
|
2790
2831
|
}
|
|
2832
|
+
await CALL_PING_CALLBACKS_FN(self, scheduled, candle.timestamp);
|
|
2791
2833
|
}
|
|
2792
2834
|
return {
|
|
2793
2835
|
activated: false,
|
|
@@ -2941,8 +2983,9 @@ class ClientStrategy {
|
|
|
2941
2983
|
this.params = params;
|
|
2942
2984
|
this._isStopped = false;
|
|
2943
2985
|
this._pendingSignal = null;
|
|
2944
|
-
this._scheduledSignal = null;
|
|
2945
2986
|
this._lastSignalTimestamp = null;
|
|
2987
|
+
this._scheduledSignal = null;
|
|
2988
|
+
this._cancelledSignal = null;
|
|
2946
2989
|
/**
|
|
2947
2990
|
* Initializes strategy state by loading persisted signal from disk.
|
|
2948
2991
|
*
|
|
@@ -3009,6 +3052,18 @@ class ClientStrategy {
|
|
|
3009
3052
|
});
|
|
3010
3053
|
return this._pendingSignal;
|
|
3011
3054
|
}
|
|
3055
|
+
/**
|
|
3056
|
+
* Retrieves the current scheduled signal.
|
|
3057
|
+
* If no scheduled signal exists, returns null.
|
|
3058
|
+
* @returns Promise resolving to the scheduled signal or null.
|
|
3059
|
+
*/
|
|
3060
|
+
async getScheduledSignal(symbol, strategyName) {
|
|
3061
|
+
this.params.logger.debug("ClientStrategy getScheduledSignal", {
|
|
3062
|
+
symbol,
|
|
3063
|
+
strategyName,
|
|
3064
|
+
});
|
|
3065
|
+
return this._scheduledSignal;
|
|
3066
|
+
}
|
|
3012
3067
|
/**
|
|
3013
3068
|
* Returns the stopped state of the strategy.
|
|
3014
3069
|
*
|
|
@@ -3068,6 +3123,33 @@ class ClientStrategy {
|
|
|
3068
3123
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
3069
3124
|
return await RETURN_IDLE_FN(this, currentPrice);
|
|
3070
3125
|
}
|
|
3126
|
+
// Check if scheduled signal was cancelled - emit cancelled event once
|
|
3127
|
+
if (this._cancelledSignal) {
|
|
3128
|
+
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
3129
|
+
const cancelledSignal = this._cancelledSignal;
|
|
3130
|
+
this._cancelledSignal = null; // Clear after emitting
|
|
3131
|
+
this.params.logger.info("ClientStrategy tick: scheduled signal was cancelled", {
|
|
3132
|
+
symbol: this.params.execution.context.symbol,
|
|
3133
|
+
signalId: cancelledSignal.id,
|
|
3134
|
+
});
|
|
3135
|
+
// Call onCancel callback
|
|
3136
|
+
if (this.params.callbacks?.onCancel) {
|
|
3137
|
+
this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
|
|
3138
|
+
}
|
|
3139
|
+
const result = {
|
|
3140
|
+
action: "cancelled",
|
|
3141
|
+
signal: cancelledSignal,
|
|
3142
|
+
currentPrice,
|
|
3143
|
+
closeTimestamp: currentTime,
|
|
3144
|
+
strategyName: this.params.method.context.strategyName,
|
|
3145
|
+
exchangeName: this.params.method.context.exchangeName,
|
|
3146
|
+
symbol: this.params.execution.context.symbol,
|
|
3147
|
+
backtest: this.params.execution.context.backtest,
|
|
3148
|
+
reason: "user",
|
|
3149
|
+
cancelId: cancelledSignal.cancelId,
|
|
3150
|
+
};
|
|
3151
|
+
return result;
|
|
3152
|
+
}
|
|
3071
3153
|
// Monitor scheduled signal
|
|
3072
3154
|
if (this._scheduledSignal && !this._pendingSignal) {
|
|
3073
3155
|
const currentPrice = await this.params.exchange.getAveragePrice(this.params.execution.context.symbol);
|
|
@@ -3158,6 +3240,29 @@ class ClientStrategy {
|
|
|
3158
3240
|
if (!this.params.execution.context.backtest) {
|
|
3159
3241
|
throw new Error("ClientStrategy backtest: running in live context");
|
|
3160
3242
|
}
|
|
3243
|
+
// If signal was cancelled - return cancelled
|
|
3244
|
+
if (this._cancelledSignal) {
|
|
3245
|
+
this.params.logger.debug("ClientStrategy backtest: no signal (cancelled or not created)");
|
|
3246
|
+
const currentPrice = await this.params.exchange.getAveragePrice(symbol);
|
|
3247
|
+
const cancelledSignal = this._cancelledSignal;
|
|
3248
|
+
this._cancelledSignal = null; // Clear after using
|
|
3249
|
+
if (this.params.callbacks?.onCancel) {
|
|
3250
|
+
this.params.callbacks.onCancel(this.params.execution.context.symbol, cancelledSignal, currentPrice, this.params.execution.context.backtest);
|
|
3251
|
+
}
|
|
3252
|
+
const cancelledResult = {
|
|
3253
|
+
action: "cancelled",
|
|
3254
|
+
signal: cancelledSignal,
|
|
3255
|
+
currentPrice,
|
|
3256
|
+
closeTimestamp: this.params.execution.context.when.getTime(),
|
|
3257
|
+
strategyName: this.params.method.context.strategyName,
|
|
3258
|
+
exchangeName: this.params.method.context.exchangeName,
|
|
3259
|
+
symbol: this.params.execution.context.symbol,
|
|
3260
|
+
backtest: true,
|
|
3261
|
+
reason: "user",
|
|
3262
|
+
cancelId: cancelledSignal.cancelId,
|
|
3263
|
+
};
|
|
3264
|
+
return cancelledResult;
|
|
3265
|
+
}
|
|
3161
3266
|
if (!this._pendingSignal && !this._scheduledSignal) {
|
|
3162
3267
|
throw new Error("ClientStrategy backtest: no pending or scheduled signal");
|
|
3163
3268
|
}
|
|
@@ -3230,7 +3335,7 @@ class ClientStrategy {
|
|
|
3230
3335
|
maxMinutes: GLOBAL_CONFIG.CC_SCHEDULE_AWAIT_MINUTES,
|
|
3231
3336
|
reason: "timeout - price never reached priceOpen",
|
|
3232
3337
|
});
|
|
3233
|
-
return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp);
|
|
3338
|
+
return await CANCEL_SCHEDULED_SIGNAL_IN_BACKTEST_FN(this, scheduled, lastPrice, lastCandleTimestamp, "timeout");
|
|
3234
3339
|
}
|
|
3235
3340
|
}
|
|
3236
3341
|
// Process pending signal
|
|
@@ -3288,6 +3393,47 @@ class ClientStrategy {
|
|
|
3288
3393
|
}
|
|
3289
3394
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3290
3395
|
}
|
|
3396
|
+
/**
|
|
3397
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
3398
|
+
*
|
|
3399
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
3400
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
3401
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
3402
|
+
*
|
|
3403
|
+
* Use case: Cancel a scheduled entry that is no longer desired without stopping the entire strategy.
|
|
3404
|
+
*
|
|
3405
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3406
|
+
* @param strategyName - Name of the strategy
|
|
3407
|
+
* @param backtest - Whether running in backtest mode
|
|
3408
|
+
* @returns Promise that resolves when scheduled signal is cleared
|
|
3409
|
+
*
|
|
3410
|
+
* @example
|
|
3411
|
+
* ```typescript
|
|
3412
|
+
* // Cancel scheduled signal without stopping strategy
|
|
3413
|
+
* await strategy.cancel("BTCUSDT", "my-strategy", false);
|
|
3414
|
+
* // Strategy continues, can generate new signals
|
|
3415
|
+
* ```
|
|
3416
|
+
*/
|
|
3417
|
+
async cancel(symbol, strategyName, backtest, cancelId) {
|
|
3418
|
+
this.params.logger.debug("ClientStrategy cancel", {
|
|
3419
|
+
symbol,
|
|
3420
|
+
strategyName,
|
|
3421
|
+
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3422
|
+
backtest,
|
|
3423
|
+
cancelId,
|
|
3424
|
+
});
|
|
3425
|
+
// Save cancelled signal for next tick to emit cancelled event
|
|
3426
|
+
if (this._scheduledSignal) {
|
|
3427
|
+
this._cancelledSignal = Object.assign({}, this._scheduledSignal, {
|
|
3428
|
+
cancelId,
|
|
3429
|
+
});
|
|
3430
|
+
this._scheduledSignal = null;
|
|
3431
|
+
}
|
|
3432
|
+
if (backtest) {
|
|
3433
|
+
return;
|
|
3434
|
+
}
|
|
3435
|
+
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, strategyName);
|
|
3436
|
+
}
|
|
3291
3437
|
}
|
|
3292
3438
|
|
|
3293
3439
|
const RISK_METHOD_NAME_GET_DATA = "RiskUtils.getData";
|
|
@@ -3614,6 +3760,27 @@ const GET_RISK_FN = (dto, backtest, self) => {
|
|
|
3614
3760
|
...dto.riskList.map((riskName) => self.riskConnectionService.getRisk(riskName, backtest)),
|
|
3615
3761
|
]);
|
|
3616
3762
|
};
|
|
3763
|
+
/**
|
|
3764
|
+
* Callback function for emitting ping events to pingSubject.
|
|
3765
|
+
*
|
|
3766
|
+
* Called by ClientStrategy when a scheduled signal is being monitored every minute.
|
|
3767
|
+
* Emits PingContract event to all subscribers.
|
|
3768
|
+
*
|
|
3769
|
+
* @param symbol - Trading pair symbol
|
|
3770
|
+
* @param strategyName - Strategy name that is monitoring this scheduled signal
|
|
3771
|
+
* @param exchangeName - Exchange name where this scheduled signal is being executed
|
|
3772
|
+
* @param data - Scheduled signal row data
|
|
3773
|
+
* @param backtest - True if backtest mode
|
|
3774
|
+
* @param timestamp - Event timestamp in milliseconds
|
|
3775
|
+
*/
|
|
3776
|
+
const COMMIT_PING_FN = async (symbol, strategyName, exchangeName, data, backtest, timestamp) => await pingSubject.next({
|
|
3777
|
+
symbol,
|
|
3778
|
+
strategyName,
|
|
3779
|
+
exchangeName,
|
|
3780
|
+
data,
|
|
3781
|
+
backtest,
|
|
3782
|
+
timestamp,
|
|
3783
|
+
});
|
|
3617
3784
|
/**
|
|
3618
3785
|
* Connection service routing strategy operations to correct ClientStrategy instance.
|
|
3619
3786
|
*
|
|
@@ -3671,6 +3838,7 @@ class StrategyConnectionService {
|
|
|
3671
3838
|
strategyName,
|
|
3672
3839
|
getSignal,
|
|
3673
3840
|
callbacks,
|
|
3841
|
+
onPing: COMMIT_PING_FN,
|
|
3674
3842
|
});
|
|
3675
3843
|
});
|
|
3676
3844
|
/**
|
|
@@ -3692,6 +3860,25 @@ class StrategyConnectionService {
|
|
|
3692
3860
|
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3693
3861
|
return await strategy.getPendingSignal(symbol, strategyName);
|
|
3694
3862
|
};
|
|
3863
|
+
/**
|
|
3864
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
3865
|
+
* If no scheduled signal exists, returns null.
|
|
3866
|
+
* Used internally for monitoring scheduled signal activation.
|
|
3867
|
+
*
|
|
3868
|
+
* @param symbol - Trading pair symbol
|
|
3869
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
3870
|
+
*
|
|
3871
|
+
* @returns Promise resolving to scheduled signal or null
|
|
3872
|
+
*/
|
|
3873
|
+
this.getScheduledSignal = async (backtest, symbol, strategyName) => {
|
|
3874
|
+
this.loggerService.log("strategyConnectionService getScheduledSignal", {
|
|
3875
|
+
symbol,
|
|
3876
|
+
strategyName,
|
|
3877
|
+
backtest,
|
|
3878
|
+
});
|
|
3879
|
+
const strategy = this.getStrategy(symbol, strategyName, backtest);
|
|
3880
|
+
return await strategy.getScheduledSignal(symbol, strategyName);
|
|
3881
|
+
};
|
|
3695
3882
|
/**
|
|
3696
3883
|
* Retrieves the stopped state of the strategy.
|
|
3697
3884
|
*
|
|
@@ -3807,6 +3994,28 @@ class StrategyConnectionService {
|
|
|
3807
3994
|
this.getStrategy.clear();
|
|
3808
3995
|
}
|
|
3809
3996
|
};
|
|
3997
|
+
/**
|
|
3998
|
+
* Cancels the scheduled signal for the specified strategy.
|
|
3999
|
+
*
|
|
4000
|
+
* Delegates to ClientStrategy.cancel() which clears the scheduled signal
|
|
4001
|
+
* without stopping the strategy or affecting pending signals.
|
|
4002
|
+
*
|
|
4003
|
+
* Note: Cancelled event will be emitted on next tick() call when strategy
|
|
4004
|
+
* detects the scheduled signal was cancelled.
|
|
4005
|
+
*
|
|
4006
|
+
* @param backtest - Whether running in backtest mode
|
|
4007
|
+
* @param ctx - Context with symbol and strategyName
|
|
4008
|
+
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
4009
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
4010
|
+
*/
|
|
4011
|
+
this.cancel = async (backtest, ctx, cancelId) => {
|
|
4012
|
+
this.loggerService.log("strategyConnectionService cancel", {
|
|
4013
|
+
ctx,
|
|
4014
|
+
cancelId,
|
|
4015
|
+
});
|
|
4016
|
+
const strategy = this.getStrategy(ctx.symbol, ctx.strategyName, backtest);
|
|
4017
|
+
await strategy.cancel(ctx.symbol, ctx.strategyName, backtest, cancelId);
|
|
4018
|
+
};
|
|
3810
4019
|
}
|
|
3811
4020
|
}
|
|
3812
4021
|
|
|
@@ -4752,6 +4961,26 @@ class StrategyCoreService {
|
|
|
4752
4961
|
await this.validate(symbol, strategyName);
|
|
4753
4962
|
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, strategyName);
|
|
4754
4963
|
};
|
|
4964
|
+
/**
|
|
4965
|
+
* Retrieves the currently active scheduled signal for the symbol.
|
|
4966
|
+
* If no scheduled signal exists, returns null.
|
|
4967
|
+
* Used internally for monitoring scheduled signal activation.
|
|
4968
|
+
*
|
|
4969
|
+
* @param symbol - Trading pair symbol
|
|
4970
|
+
* @param strategyName - Name of the strategy
|
|
4971
|
+
* @returns Promise resolving to scheduled signal or null
|
|
4972
|
+
*/
|
|
4973
|
+
this.getScheduledSignal = async (backtest, symbol, strategyName) => {
|
|
4974
|
+
this.loggerService.log("strategyCoreService getScheduledSignal", {
|
|
4975
|
+
symbol,
|
|
4976
|
+
strategyName,
|
|
4977
|
+
});
|
|
4978
|
+
if (!MethodContextService.hasContext()) {
|
|
4979
|
+
throw new Error("strategyCoreService getScheduledSignal requires a method context");
|
|
4980
|
+
}
|
|
4981
|
+
await this.validate(symbol, strategyName);
|
|
4982
|
+
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, strategyName);
|
|
4983
|
+
};
|
|
4755
4984
|
/**
|
|
4756
4985
|
* Checks if the strategy has been stopped.
|
|
4757
4986
|
*
|
|
@@ -4854,6 +5083,27 @@ class StrategyCoreService {
|
|
|
4854
5083
|
await this.validate(ctx.symbol, ctx.strategyName);
|
|
4855
5084
|
return await this.strategyConnectionService.stop(backtest, ctx);
|
|
4856
5085
|
};
|
|
5086
|
+
/**
|
|
5087
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
5088
|
+
*
|
|
5089
|
+
* Delegates to StrategyConnectionService.cancel() to clear scheduled signal
|
|
5090
|
+
* and emit cancelled event through emitters.
|
|
5091
|
+
* Does not require execution context.
|
|
5092
|
+
*
|
|
5093
|
+
* @param backtest - Whether running in backtest mode
|
|
5094
|
+
* @param ctx - Context with symbol and strategyName
|
|
5095
|
+
* @param cancelId - Optional cancellation ID for user-initiated cancellations
|
|
5096
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
5097
|
+
*/
|
|
5098
|
+
this.cancel = async (backtest, ctx, cancelId) => {
|
|
5099
|
+
this.loggerService.log("strategyCoreService cancel", {
|
|
5100
|
+
ctx,
|
|
5101
|
+
backtest,
|
|
5102
|
+
cancelId,
|
|
5103
|
+
});
|
|
5104
|
+
await this.validate(ctx.symbol, ctx.strategyName);
|
|
5105
|
+
return await this.strategyConnectionService.cancel(backtest, ctx, cancelId);
|
|
5106
|
+
};
|
|
4857
5107
|
/**
|
|
4858
5108
|
* Clears the memoized ClientStrategy instance from cache.
|
|
4859
5109
|
*
|
|
@@ -7177,12 +7427,17 @@ const risk_columns = [
|
|
|
7177
7427
|
* - Signal identification (symbol, signal ID, position)
|
|
7178
7428
|
* - Price data (current price, entry price, take profit, stop loss)
|
|
7179
7429
|
* - Timing information (wait time in minutes before activation or cancellation)
|
|
7430
|
+
* - Cancellation details (reason: timeout/stoploss/user, optional user cancel ID)
|
|
7180
7431
|
*
|
|
7181
7432
|
* @remarks
|
|
7182
7433
|
* This configuration tracks the lifecycle of scheduled signals from creation to activation or cancellation.
|
|
7183
7434
|
* The "note" column visibility is controlled by {@link GLOBAL_CONFIG.CC_REPORT_SHOW_SIGNAL_NOTE}.
|
|
7184
7435
|
* Helps analyze signal scheduling effectiveness and cancellation patterns.
|
|
7185
7436
|
*
|
|
7437
|
+
* Cancellation tracking includes:
|
|
7438
|
+
* - cancelReason: "timeout" (expired wait time), "price_reject" (price hit SL), "user" (manual cancellation)
|
|
7439
|
+
* - cancelId: Optional ID provided when calling Backtest.cancel() or Live.cancel()
|
|
7440
|
+
*
|
|
7186
7441
|
* @example
|
|
7187
7442
|
* ```typescript
|
|
7188
7443
|
* import { schedule_columns } from "./assets/schedule.columns";
|
|
@@ -7191,9 +7446,9 @@ const risk_columns = [
|
|
|
7191
7446
|
* const service = new ScheduleMarkdownService();
|
|
7192
7447
|
* await service.getReport("BTCUSDT", "my-strategy", schedule_columns);
|
|
7193
7448
|
*
|
|
7194
|
-
* // Or customize for
|
|
7449
|
+
* // Or customize for cancellation analysis
|
|
7195
7450
|
* const customColumns = schedule_columns.filter(col =>
|
|
7196
|
-
* ["timestamp", "action", "
|
|
7451
|
+
* ["timestamp", "action", "cancelReason", "cancelId"].includes(col.key)
|
|
7197
7452
|
* );
|
|
7198
7453
|
* await service.getReport("BTCUSDT", "my-strategy", customColumns);
|
|
7199
7454
|
* ```
|
|
@@ -7242,7 +7497,7 @@ const schedule_columns = [
|
|
|
7242
7497
|
{
|
|
7243
7498
|
key: "currentPrice",
|
|
7244
7499
|
label: "Current Price",
|
|
7245
|
-
format: (data) => `${data.currentPrice.toFixed(8)} USD
|
|
7500
|
+
format: (data) => data.currentPrice ? `${data.currentPrice.toFixed(8)} USD` : "N/A",
|
|
7246
7501
|
isVisible: () => true,
|
|
7247
7502
|
},
|
|
7248
7503
|
{
|
|
@@ -7269,6 +7524,18 @@ const schedule_columns = [
|
|
|
7269
7524
|
format: (data) => data.duration !== undefined ? `${data.duration}` : "N/A",
|
|
7270
7525
|
isVisible: () => true,
|
|
7271
7526
|
},
|
|
7527
|
+
{
|
|
7528
|
+
key: "cancelReason",
|
|
7529
|
+
label: "Cancel Reason",
|
|
7530
|
+
format: (data) => data.cancelReason ? data.cancelReason.toUpperCase() : "N/A",
|
|
7531
|
+
isVisible: () => true,
|
|
7532
|
+
},
|
|
7533
|
+
{
|
|
7534
|
+
key: "cancelId",
|
|
7535
|
+
label: "Cancel ID",
|
|
7536
|
+
format: (data) => data.cancelId ?? "N/A",
|
|
7537
|
+
isVisible: () => true,
|
|
7538
|
+
},
|
|
7272
7539
|
];
|
|
7273
7540
|
|
|
7274
7541
|
/**
|
|
@@ -8449,6 +8716,8 @@ let ReportStorage$3 = class ReportStorage {
|
|
|
8449
8716
|
stopLoss: data.signal.priceStopLoss,
|
|
8450
8717
|
closeTimestamp: data.closeTimestamp,
|
|
8451
8718
|
duration: durationMin,
|
|
8719
|
+
cancelReason: data.reason,
|
|
8720
|
+
cancelId: data.cancelId,
|
|
8452
8721
|
};
|
|
8453
8722
|
this._eventList.unshift(newEvent);
|
|
8454
8723
|
// Trim queue if exceeded MAX_EVENTS
|
|
@@ -14729,6 +14998,8 @@ const LISTEN_PARTIAL_LOSS_METHOD_NAME = "event.listenPartialLoss";
|
|
|
14729
14998
|
const LISTEN_PARTIAL_LOSS_ONCE_METHOD_NAME = "event.listenPartialLossOnce";
|
|
14730
14999
|
const LISTEN_RISK_METHOD_NAME = "event.listenRisk";
|
|
14731
15000
|
const LISTEN_RISK_ONCE_METHOD_NAME = "event.listenRiskOnce";
|
|
15001
|
+
const LISTEN_PING_METHOD_NAME = "event.listenPing";
|
|
15002
|
+
const LISTEN_PING_ONCE_METHOD_NAME = "event.listenPingOnce";
|
|
14732
15003
|
/**
|
|
14733
15004
|
* Subscribes to all signal events with queued async processing.
|
|
14734
15005
|
*
|
|
@@ -15596,6 +15867,67 @@ function listenRiskOnce(filterFn, fn) {
|
|
|
15596
15867
|
backtest$1.loggerService.log(LISTEN_RISK_ONCE_METHOD_NAME);
|
|
15597
15868
|
return riskSubject.filter(filterFn).once(fn);
|
|
15598
15869
|
}
|
|
15870
|
+
/**
|
|
15871
|
+
* Subscribes to ping events during scheduled signal monitoring with queued async processing.
|
|
15872
|
+
*
|
|
15873
|
+
* Events are emitted every minute when a scheduled signal is being monitored (waiting for activation).
|
|
15874
|
+
* Allows tracking of scheduled signal lifecycle and custom monitoring logic.
|
|
15875
|
+
*
|
|
15876
|
+
* @param fn - Callback function to handle ping events
|
|
15877
|
+
* @returns Unsubscribe function to stop listening
|
|
15878
|
+
*
|
|
15879
|
+
* @example
|
|
15880
|
+
* ```typescript
|
|
15881
|
+
* import { listenPing } from "./function/event";
|
|
15882
|
+
*
|
|
15883
|
+
* const unsubscribe = listenPing((event) => {
|
|
15884
|
+
* console.log(`Ping for ${event.symbol} at ${new Date(event.timestamp).toISOString()}`);
|
|
15885
|
+
* console.log(`Strategy: ${event.strategyName}, Exchange: ${event.exchangeName}`);
|
|
15886
|
+
* console.log(`Mode: ${event.backtest ? "Backtest" : "Live"}`);
|
|
15887
|
+
* });
|
|
15888
|
+
*
|
|
15889
|
+
* // Later: stop listening
|
|
15890
|
+
* unsubscribe();
|
|
15891
|
+
* ```
|
|
15892
|
+
*/
|
|
15893
|
+
function listenPing(fn) {
|
|
15894
|
+
backtest$1.loggerService.log(LISTEN_PING_METHOD_NAME);
|
|
15895
|
+
return pingSubject.subscribe(functoolsKit.queued(async (event) => fn(event)));
|
|
15896
|
+
}
|
|
15897
|
+
/**
|
|
15898
|
+
* Subscribes to filtered ping events with one-time execution.
|
|
15899
|
+
*
|
|
15900
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
15901
|
+
* and automatically unsubscribes. Useful for waiting for specific ping conditions.
|
|
15902
|
+
*
|
|
15903
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
15904
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
15905
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
15906
|
+
*
|
|
15907
|
+
* @example
|
|
15908
|
+
* ```typescript
|
|
15909
|
+
* import { listenPingOnce } from "./function/event";
|
|
15910
|
+
*
|
|
15911
|
+
* // Wait for first ping on BTCUSDT
|
|
15912
|
+
* listenPingOnce(
|
|
15913
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
15914
|
+
* (event) => console.log("First BTCUSDT ping received")
|
|
15915
|
+
* );
|
|
15916
|
+
*
|
|
15917
|
+
* // Wait for ping in backtest mode
|
|
15918
|
+
* const cancel = listenPingOnce(
|
|
15919
|
+
* (event) => event.backtest === true,
|
|
15920
|
+
* (event) => console.log("Backtest ping received at", new Date(event.timestamp))
|
|
15921
|
+
* );
|
|
15922
|
+
*
|
|
15923
|
+
* // Cancel if needed before event fires
|
|
15924
|
+
* cancel();
|
|
15925
|
+
* ```
|
|
15926
|
+
*/
|
|
15927
|
+
function listenPingOnce(filterFn, fn) {
|
|
15928
|
+
backtest$1.loggerService.log(LISTEN_PING_ONCE_METHOD_NAME);
|
|
15929
|
+
return pingSubject.filter(filterFn).once(fn);
|
|
15930
|
+
}
|
|
15599
15931
|
|
|
15600
15932
|
const GET_CANDLES_METHOD_NAME = "exchange.getCandles";
|
|
15601
15933
|
const GET_AVERAGE_PRICE_METHOD_NAME = "exchange.getAveragePrice";
|
|
@@ -15869,6 +16201,8 @@ const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
|
|
|
15869
16201
|
const BACKTEST_METHOD_NAME_DUMP = "BacktestUtils.dump";
|
|
15870
16202
|
const BACKTEST_METHOD_NAME_TASK = "BacktestUtils.task";
|
|
15871
16203
|
const BACKTEST_METHOD_NAME_GET_STATUS = "BacktestUtils.getStatus";
|
|
16204
|
+
const BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL = "BacktestUtils.getPendingSignal";
|
|
16205
|
+
const BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL = "BacktestUtils.getScheduledSignal";
|
|
15872
16206
|
/**
|
|
15873
16207
|
* Internal task function that runs backtest and handles completion.
|
|
15874
16208
|
* Consumes backtest results and updates instance state flags.
|
|
@@ -16059,6 +16393,54 @@ class BacktestInstance {
|
|
|
16059
16393
|
this._isStopped = true;
|
|
16060
16394
|
};
|
|
16061
16395
|
};
|
|
16396
|
+
/**
|
|
16397
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
16398
|
+
* If no active signal exists, returns null.
|
|
16399
|
+
*
|
|
16400
|
+
* @param symbol - Trading pair symbol
|
|
16401
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
16402
|
+
* @returns Promise resolving to pending signal or null
|
|
16403
|
+
*
|
|
16404
|
+
* @example
|
|
16405
|
+
* ```typescript
|
|
16406
|
+
* const instance = new BacktestInstance();
|
|
16407
|
+
* const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
|
|
16408
|
+
* if (pending) {
|
|
16409
|
+
* console.log("Active signal:", pending.id);
|
|
16410
|
+
* }
|
|
16411
|
+
* ```
|
|
16412
|
+
*/
|
|
16413
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
16414
|
+
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL, {
|
|
16415
|
+
symbol,
|
|
16416
|
+
strategyName,
|
|
16417
|
+
});
|
|
16418
|
+
return await backtest$1.strategyCoreService.getPendingSignal(true, symbol, strategyName);
|
|
16419
|
+
};
|
|
16420
|
+
/**
|
|
16421
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
16422
|
+
* If no scheduled signal exists, returns null.
|
|
16423
|
+
*
|
|
16424
|
+
* @param symbol - Trading pair symbol
|
|
16425
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
16426
|
+
* @returns Promise resolving to scheduled signal or null
|
|
16427
|
+
*
|
|
16428
|
+
* @example
|
|
16429
|
+
* ```typescript
|
|
16430
|
+
* const instance = new BacktestInstance();
|
|
16431
|
+
* const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
16432
|
+
* if (scheduled) {
|
|
16433
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
16434
|
+
* }
|
|
16435
|
+
* ```
|
|
16436
|
+
*/
|
|
16437
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
16438
|
+
backtest$1.loggerService.info(BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
|
|
16439
|
+
symbol,
|
|
16440
|
+
strategyName,
|
|
16441
|
+
});
|
|
16442
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(true, symbol, strategyName);
|
|
16443
|
+
};
|
|
16062
16444
|
/**
|
|
16063
16445
|
* Stops the strategy from generating new signals.
|
|
16064
16446
|
*
|
|
@@ -16083,6 +16465,32 @@ class BacktestInstance {
|
|
|
16083
16465
|
});
|
|
16084
16466
|
await backtest$1.strategyCoreService.stop(true, { symbol, strategyName });
|
|
16085
16467
|
};
|
|
16468
|
+
/**
|
|
16469
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
16470
|
+
*
|
|
16471
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
16472
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
16473
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
16474
|
+
*
|
|
16475
|
+
* @param symbol - Trading pair symbol
|
|
16476
|
+
* @param strategyName - Strategy name
|
|
16477
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
16478
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
16479
|
+
*
|
|
16480
|
+
* @example
|
|
16481
|
+
* ```typescript
|
|
16482
|
+
* const instance = new BacktestInstance();
|
|
16483
|
+
* await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
16484
|
+
* ```
|
|
16485
|
+
*/
|
|
16486
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
16487
|
+
backtest$1.loggerService.info("BacktestInstance.cancel", {
|
|
16488
|
+
symbol,
|
|
16489
|
+
strategyName,
|
|
16490
|
+
cancelId,
|
|
16491
|
+
});
|
|
16492
|
+
await backtest$1.strategyCoreService.cancel(true, { symbol, strategyName }, cancelId);
|
|
16493
|
+
};
|
|
16086
16494
|
/**
|
|
16087
16495
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
16088
16496
|
*
|
|
@@ -16234,6 +16642,58 @@ class BacktestUtils {
|
|
|
16234
16642
|
const instance = this._getInstance(symbol, context.strategyName);
|
|
16235
16643
|
return instance.background(symbol, context);
|
|
16236
16644
|
};
|
|
16645
|
+
/**
|
|
16646
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
16647
|
+
* If no active signal exists, returns null.
|
|
16648
|
+
*
|
|
16649
|
+
* @param symbol - Trading pair symbol
|
|
16650
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
16651
|
+
* @returns Promise resolving to pending signal or null
|
|
16652
|
+
*
|
|
16653
|
+
* @example
|
|
16654
|
+
* ```typescript
|
|
16655
|
+
* const pending = await Backtest.getPendingSignal("BTCUSDT", "my-strategy");
|
|
16656
|
+
* if (pending) {
|
|
16657
|
+
* console.log("Active signal:", pending.id);
|
|
16658
|
+
* }
|
|
16659
|
+
* ```
|
|
16660
|
+
*/
|
|
16661
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
16662
|
+
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16663
|
+
{
|
|
16664
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16665
|
+
riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
16666
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
16667
|
+
}
|
|
16668
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16669
|
+
return await instance.getPendingSignal(symbol, strategyName);
|
|
16670
|
+
};
|
|
16671
|
+
/**
|
|
16672
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
16673
|
+
* If no scheduled signal exists, returns null.
|
|
16674
|
+
*
|
|
16675
|
+
* @param symbol - Trading pair symbol
|
|
16676
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
16677
|
+
* @returns Promise resolving to scheduled signal or null
|
|
16678
|
+
*
|
|
16679
|
+
* @example
|
|
16680
|
+
* ```typescript
|
|
16681
|
+
* const scheduled = await Backtest.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
16682
|
+
* if (scheduled) {
|
|
16683
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
16684
|
+
* }
|
|
16685
|
+
* ```
|
|
16686
|
+
*/
|
|
16687
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
16688
|
+
backtest$1.strategyValidationService.validate(strategyName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16689
|
+
{
|
|
16690
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16691
|
+
riskName && backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
16692
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
16693
|
+
}
|
|
16694
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16695
|
+
return await instance.getScheduledSignal(symbol, strategyName);
|
|
16696
|
+
};
|
|
16237
16697
|
/**
|
|
16238
16698
|
* Stops the strategy from generating new signals.
|
|
16239
16699
|
*
|
|
@@ -16261,6 +16721,34 @@ class BacktestUtils {
|
|
|
16261
16721
|
const instance = this._getInstance(symbol, strategyName);
|
|
16262
16722
|
return await instance.stop(symbol, strategyName);
|
|
16263
16723
|
};
|
|
16724
|
+
/**
|
|
16725
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
16726
|
+
*
|
|
16727
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
16728
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
16729
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
16730
|
+
*
|
|
16731
|
+
* @param symbol - Trading pair symbol
|
|
16732
|
+
* @param strategyName - Strategy name
|
|
16733
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
16734
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
16735
|
+
*
|
|
16736
|
+
* @example
|
|
16737
|
+
* ```typescript
|
|
16738
|
+
* // Cancel scheduled signal with custom ID
|
|
16739
|
+
* await Backtest.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
16740
|
+
* ```
|
|
16741
|
+
*/
|
|
16742
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
16743
|
+
backtest$1.strategyValidationService.validate(strategyName, "BacktestUtils.cancel");
|
|
16744
|
+
{
|
|
16745
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
16746
|
+
riskName && backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel");
|
|
16747
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, "BacktestUtils.cancel"));
|
|
16748
|
+
}
|
|
16749
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
16750
|
+
return await instance.cancel(symbol, strategyName, cancelId);
|
|
16751
|
+
};
|
|
16264
16752
|
/**
|
|
16265
16753
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
16266
16754
|
*
|
|
@@ -16382,6 +16870,9 @@ const LIVE_METHOD_NAME_GET_DATA = "LiveUtils.getData";
|
|
|
16382
16870
|
const LIVE_METHOD_NAME_DUMP = "LiveUtils.dump";
|
|
16383
16871
|
const LIVE_METHOD_NAME_TASK = "LiveUtils.task";
|
|
16384
16872
|
const LIVE_METHOD_NAME_GET_STATUS = "LiveUtils.getStatus";
|
|
16873
|
+
const LIVE_METHOD_NAME_GET_PENDING_SIGNAL = "LiveUtils.getPendingSignal";
|
|
16874
|
+
const LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL = "LiveUtils.getScheduledSignal";
|
|
16875
|
+
const LIVE_METHOD_NAME_CANCEL = "LiveUtils.cancel";
|
|
16385
16876
|
/**
|
|
16386
16877
|
* Internal task function that runs live trading and handles completion.
|
|
16387
16878
|
* Consumes live trading results and updates instance state flags.
|
|
@@ -16576,6 +17067,54 @@ class LiveInstance {
|
|
|
16576
17067
|
this._isStopped = true;
|
|
16577
17068
|
};
|
|
16578
17069
|
};
|
|
17070
|
+
/**
|
|
17071
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
17072
|
+
* If no active signal exists, returns null.
|
|
17073
|
+
*
|
|
17074
|
+
* @param symbol - Trading pair symbol
|
|
17075
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
17076
|
+
* @returns Promise resolving to pending signal or null
|
|
17077
|
+
*
|
|
17078
|
+
* @example
|
|
17079
|
+
* ```typescript
|
|
17080
|
+
* const instance = new LiveInstance();
|
|
17081
|
+
* const pending = await instance.getPendingSignal("BTCUSDT", "my-strategy");
|
|
17082
|
+
* if (pending) {
|
|
17083
|
+
* console.log("Active signal:", pending.id);
|
|
17084
|
+
* }
|
|
17085
|
+
* ```
|
|
17086
|
+
*/
|
|
17087
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
17088
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_PENDING_SIGNAL, {
|
|
17089
|
+
symbol,
|
|
17090
|
+
strategyName,
|
|
17091
|
+
});
|
|
17092
|
+
return await backtest$1.strategyCoreService.getPendingSignal(false, symbol, strategyName);
|
|
17093
|
+
};
|
|
17094
|
+
/**
|
|
17095
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
17096
|
+
* If no scheduled signal exists, returns null.
|
|
17097
|
+
*
|
|
17098
|
+
* @param symbol - Trading pair symbol
|
|
17099
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
17100
|
+
* @returns Promise resolving to scheduled signal or null
|
|
17101
|
+
*
|
|
17102
|
+
* @example
|
|
17103
|
+
* ```typescript
|
|
17104
|
+
* const instance = new LiveInstance();
|
|
17105
|
+
* const scheduled = await instance.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
17106
|
+
* if (scheduled) {
|
|
17107
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
17108
|
+
* }
|
|
17109
|
+
* ```
|
|
17110
|
+
*/
|
|
17111
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
17112
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL, {
|
|
17113
|
+
symbol,
|
|
17114
|
+
strategyName,
|
|
17115
|
+
});
|
|
17116
|
+
return await backtest$1.strategyCoreService.getScheduledSignal(false, symbol, strategyName);
|
|
17117
|
+
};
|
|
16579
17118
|
/**
|
|
16580
17119
|
* Stops the strategy from generating new signals.
|
|
16581
17120
|
*
|
|
@@ -16600,6 +17139,32 @@ class LiveInstance {
|
|
|
16600
17139
|
});
|
|
16601
17140
|
await backtest$1.strategyCoreService.stop(false, { symbol, strategyName });
|
|
16602
17141
|
};
|
|
17142
|
+
/**
|
|
17143
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
17144
|
+
*
|
|
17145
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
17146
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
17147
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
17148
|
+
*
|
|
17149
|
+
* @param symbol - Trading pair symbol
|
|
17150
|
+
* @param strategyName - Strategy name
|
|
17151
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
17152
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
17153
|
+
*
|
|
17154
|
+
* @example
|
|
17155
|
+
* ```typescript
|
|
17156
|
+
* const instance = new LiveInstance();
|
|
17157
|
+
* await instance.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
17158
|
+
* ```
|
|
17159
|
+
*/
|
|
17160
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
17161
|
+
backtest$1.loggerService.info(LIVE_METHOD_NAME_CANCEL, {
|
|
17162
|
+
symbol,
|
|
17163
|
+
strategyName,
|
|
17164
|
+
cancelId,
|
|
17165
|
+
});
|
|
17166
|
+
await backtest$1.strategyCoreService.cancel(false, { symbol, strategyName }, cancelId);
|
|
17167
|
+
};
|
|
16603
17168
|
/**
|
|
16604
17169
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
16605
17170
|
*
|
|
@@ -16762,6 +17327,58 @@ class LiveUtils {
|
|
|
16762
17327
|
const instance = this._getInstance(symbol, context.strategyName);
|
|
16763
17328
|
return instance.background(symbol, context);
|
|
16764
17329
|
};
|
|
17330
|
+
/**
|
|
17331
|
+
* Retrieves the currently active pending signal for the strategy.
|
|
17332
|
+
* If no active signal exists, returns null.
|
|
17333
|
+
*
|
|
17334
|
+
* @param symbol - Trading pair symbol
|
|
17335
|
+
* @param strategyName - Name of strategy to get pending signal for
|
|
17336
|
+
* @returns Promise resolving to pending signal or null
|
|
17337
|
+
*
|
|
17338
|
+
* @example
|
|
17339
|
+
* ```typescript
|
|
17340
|
+
* const pending = await Live.getPendingSignal("BTCUSDT", "my-strategy");
|
|
17341
|
+
* if (pending) {
|
|
17342
|
+
* console.log("Active signal:", pending.id);
|
|
17343
|
+
* }
|
|
17344
|
+
* ```
|
|
17345
|
+
*/
|
|
17346
|
+
this.getPendingSignal = async (symbol, strategyName) => {
|
|
17347
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17348
|
+
{
|
|
17349
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17350
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL);
|
|
17351
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_PENDING_SIGNAL));
|
|
17352
|
+
}
|
|
17353
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17354
|
+
return await instance.getPendingSignal(symbol, strategyName);
|
|
17355
|
+
};
|
|
17356
|
+
/**
|
|
17357
|
+
* Retrieves the currently active scheduled signal for the strategy.
|
|
17358
|
+
* If no scheduled signal exists, returns null.
|
|
17359
|
+
*
|
|
17360
|
+
* @param symbol - Trading pair symbol
|
|
17361
|
+
* @param strategyName - Name of strategy to get scheduled signal for
|
|
17362
|
+
* @returns Promise resolving to scheduled signal or null
|
|
17363
|
+
*
|
|
17364
|
+
* @example
|
|
17365
|
+
* ```typescript
|
|
17366
|
+
* const scheduled = await Live.getScheduledSignal("BTCUSDT", "my-strategy");
|
|
17367
|
+
* if (scheduled) {
|
|
17368
|
+
* console.log("Scheduled signal:", scheduled.id);
|
|
17369
|
+
* }
|
|
17370
|
+
* ```
|
|
17371
|
+
*/
|
|
17372
|
+
this.getScheduledSignal = async (symbol, strategyName) => {
|
|
17373
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17374
|
+
{
|
|
17375
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17376
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL);
|
|
17377
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_SCHEDULED_SIGNAL));
|
|
17378
|
+
}
|
|
17379
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17380
|
+
return await instance.getScheduledSignal(symbol, strategyName);
|
|
17381
|
+
};
|
|
16765
17382
|
/**
|
|
16766
17383
|
* Stops the strategy from generating new signals.
|
|
16767
17384
|
*
|
|
@@ -16789,6 +17406,34 @@ class LiveUtils {
|
|
|
16789
17406
|
const instance = this._getInstance(symbol, strategyName);
|
|
16790
17407
|
return await instance.stop(symbol, strategyName);
|
|
16791
17408
|
};
|
|
17409
|
+
/**
|
|
17410
|
+
* Cancels the scheduled signal without stopping the strategy.
|
|
17411
|
+
*
|
|
17412
|
+
* Clears the scheduled signal (waiting for priceOpen activation).
|
|
17413
|
+
* Does NOT affect active pending signals or strategy operation.
|
|
17414
|
+
* Does NOT set stop flag - strategy can continue generating new signals.
|
|
17415
|
+
*
|
|
17416
|
+
* @param symbol - Trading pair symbol
|
|
17417
|
+
* @param strategyName - Strategy name
|
|
17418
|
+
* @param cancelId - Optional cancellation ID for tracking user-initiated cancellations
|
|
17419
|
+
* @returns Promise that resolves when scheduled signal is cancelled
|
|
17420
|
+
*
|
|
17421
|
+
* @example
|
|
17422
|
+
* ```typescript
|
|
17423
|
+
* // Cancel scheduled signal in live trading with custom ID
|
|
17424
|
+
* await Live.cancel("BTCUSDT", "my-strategy", "manual-cancel-001");
|
|
17425
|
+
* ```
|
|
17426
|
+
*/
|
|
17427
|
+
this.cancel = async (symbol, strategyName, cancelId) => {
|
|
17428
|
+
backtest$1.strategyValidationService.validate(strategyName, LIVE_METHOD_NAME_CANCEL);
|
|
17429
|
+
{
|
|
17430
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
17431
|
+
riskName && backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL);
|
|
17432
|
+
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, LIVE_METHOD_NAME_CANCEL));
|
|
17433
|
+
}
|
|
17434
|
+
const instance = this._getInstance(symbol, strategyName);
|
|
17435
|
+
return await instance.cancel(symbol, strategyName, cancelId);
|
|
17436
|
+
};
|
|
16792
17437
|
/**
|
|
16793
17438
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
16794
17439
|
*
|
|
@@ -19012,6 +19657,8 @@ exports.listenPartialLossOnce = listenPartialLossOnce;
|
|
|
19012
19657
|
exports.listenPartialProfit = listenPartialProfit;
|
|
19013
19658
|
exports.listenPartialProfitOnce = listenPartialProfitOnce;
|
|
19014
19659
|
exports.listenPerformance = listenPerformance;
|
|
19660
|
+
exports.listenPing = listenPing;
|
|
19661
|
+
exports.listenPingOnce = listenPingOnce;
|
|
19015
19662
|
exports.listenRisk = listenRisk;
|
|
19016
19663
|
exports.listenRiskOnce = listenRiskOnce;
|
|
19017
19664
|
exports.listenSignal = listenSignal;
|