backtest-kit 6.13.0 → 6.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +1024 -132
- package/build/index.mjs +1020 -133
- package/package.json +2 -2
- package/types.d.ts +641 -10
package/build/index.cjs
CHANGED
|
@@ -147,6 +147,9 @@ const reportServices$1 = {
|
|
|
147
147
|
highestProfitReportService: Symbol('highestProfitReportService'),
|
|
148
148
|
maxDrawdownReportService: Symbol('maxDrawdownReportService'),
|
|
149
149
|
};
|
|
150
|
+
const helperServices$1 = {
|
|
151
|
+
notificationHelperService: Symbol('notificationHelperService'),
|
|
152
|
+
};
|
|
150
153
|
const validationServices$1 = {
|
|
151
154
|
exchangeValidationService: Symbol('exchangeValidationService'),
|
|
152
155
|
strategyValidationService: Symbol('strategyValidationService'),
|
|
@@ -172,6 +175,7 @@ const TYPES = {
|
|
|
172
175
|
...markdownServices$1,
|
|
173
176
|
...reportServices$1,
|
|
174
177
|
...validationServices$1,
|
|
178
|
+
...helperServices$1,
|
|
175
179
|
};
|
|
176
180
|
|
|
177
181
|
/**
|
|
@@ -764,6 +768,11 @@ const highestProfitSubject = new functoolsKit.Subject();
|
|
|
764
768
|
* Allows users to track drawdown levels and implement custom risk management logic based on drawdown thresholds.
|
|
765
769
|
*/
|
|
766
770
|
const maxDrawdownSubject = new functoolsKit.Subject();
|
|
771
|
+
/**
|
|
772
|
+
* Signal info emitter for user-defined informational notes on open positions.
|
|
773
|
+
* Emits when a strategy calls commitSignalInfo() to broadcast a custom annotation.
|
|
774
|
+
*/
|
|
775
|
+
const signalNotifySubject = new functoolsKit.Subject();
|
|
767
776
|
|
|
768
777
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
769
778
|
__proto__: null,
|
|
@@ -788,6 +797,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
788
797
|
signalBacktestEmitter: signalBacktestEmitter,
|
|
789
798
|
signalEmitter: signalEmitter,
|
|
790
799
|
signalLiveEmitter: signalLiveEmitter,
|
|
800
|
+
signalNotifySubject: signalNotifySubject,
|
|
791
801
|
strategyCommitSubject: strategyCommitSubject,
|
|
792
802
|
syncSubject: syncSubject,
|
|
793
803
|
validationSubject: validationSubject,
|
|
@@ -7973,6 +7983,40 @@ class ClientStrategy {
|
|
|
7973
7983
|
}
|
|
7974
7984
|
return Math.floor((timestamp - this._pendingSignal._peak.timestamp) / 60000);
|
|
7975
7985
|
}
|
|
7986
|
+
/**
|
|
7987
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
7988
|
+
*
|
|
7989
|
+
* Computed as elapsed minutes since `pendingAt` (the moment the signal was activated).
|
|
7990
|
+
* Returns null if no pending signal exists.
|
|
7991
|
+
*
|
|
7992
|
+
* @param symbol - Trading pair symbol
|
|
7993
|
+
* @param timestamp - Current Unix timestamp in milliseconds
|
|
7994
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
7995
|
+
*/
|
|
7996
|
+
async getPositionActiveMinutes(symbol, timestamp) {
|
|
7997
|
+
this.params.logger.debug("ClientStrategy getPositionActiveMinutes", { symbol });
|
|
7998
|
+
if (!this._pendingSignal) {
|
|
7999
|
+
return null;
|
|
8000
|
+
}
|
|
8001
|
+
return Math.floor((timestamp - this._pendingSignal.pendingAt) / 60000);
|
|
8002
|
+
}
|
|
8003
|
+
/**
|
|
8004
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
8005
|
+
*
|
|
8006
|
+
* Computed as elapsed minutes since `scheduledAt` (the moment the scheduled signal was created).
|
|
8007
|
+
* Returns null if no scheduled signal exists.
|
|
8008
|
+
*
|
|
8009
|
+
* @param symbol - Trading pair symbol
|
|
8010
|
+
* @param timestamp - Current Unix timestamp in milliseconds
|
|
8011
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
8012
|
+
*/
|
|
8013
|
+
async getPositionWaitingMinutes(symbol, timestamp) {
|
|
8014
|
+
this.params.logger.debug("ClientStrategy getPositionWaitingMinutes", { symbol });
|
|
8015
|
+
if (!this._scheduledSignal) {
|
|
8016
|
+
return null;
|
|
8017
|
+
}
|
|
8018
|
+
return Math.floor((timestamp - this._scheduledSignal.scheduledAt) / 60000);
|
|
8019
|
+
}
|
|
7976
8020
|
/**
|
|
7977
8021
|
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
7978
8022
|
*
|
|
@@ -10290,7 +10334,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
10290
10334
|
* @param backtest - Whether running in backtest mode
|
|
10291
10335
|
* @returns Unique string key for memoization
|
|
10292
10336
|
*/
|
|
10293
|
-
const CREATE_KEY_FN$
|
|
10337
|
+
const CREATE_KEY_FN$v = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10294
10338
|
const parts = [symbol, strategyName, exchangeName];
|
|
10295
10339
|
if (frameName)
|
|
10296
10340
|
parts.push(frameName);
|
|
@@ -10557,7 +10601,7 @@ class StrategyConnectionService {
|
|
|
10557
10601
|
* @param backtest - Whether running in backtest mode
|
|
10558
10602
|
* @returns Configured ClientStrategy instance
|
|
10559
10603
|
*/
|
|
10560
|
-
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
10604
|
+
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$v(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10561
10605
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
10562
10606
|
return new ClientStrategy({
|
|
10563
10607
|
symbol,
|
|
@@ -11074,6 +11118,46 @@ class StrategyConnectionService {
|
|
|
11074
11118
|
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
11075
11119
|
return await strategy.getPositionCountdownMinutes(symbol, timestamp);
|
|
11076
11120
|
};
|
|
11121
|
+
/**
|
|
11122
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
11123
|
+
*
|
|
11124
|
+
* Delegates to ClientStrategy.getPositionActiveMinutes().
|
|
11125
|
+
* Returns null if no pending signal exists.
|
|
11126
|
+
*
|
|
11127
|
+
* @param backtest - Whether running in backtest mode
|
|
11128
|
+
* @param symbol - Trading pair symbol
|
|
11129
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11130
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
11131
|
+
*/
|
|
11132
|
+
this.getPositionActiveMinutes = async (backtest, symbol, context) => {
|
|
11133
|
+
this.loggerService.log("strategyConnectionService getPositionActiveMinutes", {
|
|
11134
|
+
symbol,
|
|
11135
|
+
context,
|
|
11136
|
+
});
|
|
11137
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11138
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
11139
|
+
return await strategy.getPositionActiveMinutes(symbol, timestamp);
|
|
11140
|
+
};
|
|
11141
|
+
/**
|
|
11142
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
11143
|
+
*
|
|
11144
|
+
* Delegates to ClientStrategy.getPositionWaitingMinutes().
|
|
11145
|
+
* Returns null if no scheduled signal exists.
|
|
11146
|
+
*
|
|
11147
|
+
* @param backtest - Whether running in backtest mode
|
|
11148
|
+
* @param symbol - Trading pair symbol
|
|
11149
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11150
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
11151
|
+
*/
|
|
11152
|
+
this.getPositionWaitingMinutes = async (backtest, symbol, context) => {
|
|
11153
|
+
this.loggerService.log("strategyConnectionService getPositionWaitingMinutes", {
|
|
11154
|
+
symbol,
|
|
11155
|
+
context,
|
|
11156
|
+
});
|
|
11157
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11158
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
11159
|
+
return await strategy.getPositionWaitingMinutes(symbol, timestamp);
|
|
11160
|
+
};
|
|
11077
11161
|
/**
|
|
11078
11162
|
* Returns the best price reached in the profit direction during this position's life.
|
|
11079
11163
|
*
|
|
@@ -11478,7 +11562,7 @@ class StrategyConnectionService {
|
|
|
11478
11562
|
}
|
|
11479
11563
|
return;
|
|
11480
11564
|
}
|
|
11481
|
-
const key = CREATE_KEY_FN$
|
|
11565
|
+
const key = CREATE_KEY_FN$v(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
11482
11566
|
if (!this.getStrategy.has(key)) {
|
|
11483
11567
|
return;
|
|
11484
11568
|
}
|
|
@@ -12647,7 +12731,7 @@ class ClientRisk {
|
|
|
12647
12731
|
* @param backtest - Whether running in backtest mode
|
|
12648
12732
|
* @returns Unique string key for memoization
|
|
12649
12733
|
*/
|
|
12650
|
-
const CREATE_KEY_FN$
|
|
12734
|
+
const CREATE_KEY_FN$u = (riskName, exchangeName, frameName, backtest) => {
|
|
12651
12735
|
const parts = [riskName, exchangeName];
|
|
12652
12736
|
if (frameName)
|
|
12653
12737
|
parts.push(frameName);
|
|
@@ -12747,7 +12831,7 @@ class RiskConnectionService {
|
|
|
12747
12831
|
* @param backtest - True if backtest mode, false if live mode
|
|
12748
12832
|
* @returns Configured ClientRisk instance
|
|
12749
12833
|
*/
|
|
12750
|
-
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
12834
|
+
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$u(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
12751
12835
|
const schema = this.riskSchemaService.get(riskName);
|
|
12752
12836
|
return new ClientRisk({
|
|
12753
12837
|
...schema,
|
|
@@ -12816,7 +12900,7 @@ class RiskConnectionService {
|
|
|
12816
12900
|
payload,
|
|
12817
12901
|
});
|
|
12818
12902
|
if (payload) {
|
|
12819
|
-
const key = CREATE_KEY_FN$
|
|
12903
|
+
const key = CREATE_KEY_FN$u(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
12820
12904
|
this.getRisk.clear(key);
|
|
12821
12905
|
}
|
|
12822
12906
|
else {
|
|
@@ -13860,7 +13944,7 @@ class ClientAction {
|
|
|
13860
13944
|
* @param backtest - Whether running in backtest mode
|
|
13861
13945
|
* @returns Unique string key for memoization
|
|
13862
13946
|
*/
|
|
13863
|
-
const CREATE_KEY_FN$
|
|
13947
|
+
const CREATE_KEY_FN$t = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13864
13948
|
const parts = [actionName, strategyName, exchangeName];
|
|
13865
13949
|
if (frameName)
|
|
13866
13950
|
parts.push(frameName);
|
|
@@ -13912,7 +13996,7 @@ class ActionConnectionService {
|
|
|
13912
13996
|
* @param backtest - True if backtest mode, false if live mode
|
|
13913
13997
|
* @returns Configured ClientAction instance
|
|
13914
13998
|
*/
|
|
13915
|
-
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
13999
|
+
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$t(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13916
14000
|
const schema = this.actionSchemaService.get(actionName);
|
|
13917
14001
|
return new ClientAction({
|
|
13918
14002
|
...schema,
|
|
@@ -14123,7 +14207,7 @@ class ActionConnectionService {
|
|
|
14123
14207
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
14124
14208
|
return;
|
|
14125
14209
|
}
|
|
14126
|
-
const key = CREATE_KEY_FN$
|
|
14210
|
+
const key = CREATE_KEY_FN$t(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
14127
14211
|
if (!this.getAction.has(key)) {
|
|
14128
14212
|
return;
|
|
14129
14213
|
}
|
|
@@ -14134,14 +14218,14 @@ class ActionConnectionService {
|
|
|
14134
14218
|
}
|
|
14135
14219
|
}
|
|
14136
14220
|
|
|
14137
|
-
const METHOD_NAME_VALIDATE$
|
|
14221
|
+
const METHOD_NAME_VALIDATE$3 = "exchangeCoreService validate";
|
|
14138
14222
|
/**
|
|
14139
14223
|
* Creates a unique key for memoizing validate calls.
|
|
14140
14224
|
* Key format: "exchangeName"
|
|
14141
14225
|
* @param exchangeName - Exchange name
|
|
14142
14226
|
* @returns Unique string key for memoization
|
|
14143
14227
|
*/
|
|
14144
|
-
const CREATE_KEY_FN$
|
|
14228
|
+
const CREATE_KEY_FN$s = (exchangeName) => {
|
|
14145
14229
|
return exchangeName;
|
|
14146
14230
|
};
|
|
14147
14231
|
/**
|
|
@@ -14165,11 +14249,11 @@ class ExchangeCoreService {
|
|
|
14165
14249
|
* @param exchangeName - Name of the exchange to validate
|
|
14166
14250
|
* @returns Promise that resolves when validation is complete
|
|
14167
14251
|
*/
|
|
14168
|
-
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
14169
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14252
|
+
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$s(exchangeName), async (exchangeName) => {
|
|
14253
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$3, {
|
|
14170
14254
|
exchangeName,
|
|
14171
14255
|
});
|
|
14172
|
-
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$
|
|
14256
|
+
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$3);
|
|
14173
14257
|
});
|
|
14174
14258
|
/**
|
|
14175
14259
|
* Fetches historical candles with execution context.
|
|
@@ -14410,14 +14494,14 @@ class ExchangeCoreService {
|
|
|
14410
14494
|
}
|
|
14411
14495
|
}
|
|
14412
14496
|
|
|
14413
|
-
const METHOD_NAME_VALIDATE$
|
|
14497
|
+
const METHOD_NAME_VALIDATE$2 = "strategyCoreService validate";
|
|
14414
14498
|
/**
|
|
14415
14499
|
* Creates a unique key for memoizing validate calls.
|
|
14416
14500
|
* Key format: "strategyName:exchangeName:frameName"
|
|
14417
14501
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14418
14502
|
* @returns Unique string key for memoization
|
|
14419
14503
|
*/
|
|
14420
|
-
const CREATE_KEY_FN$
|
|
14504
|
+
const CREATE_KEY_FN$r = (context) => {
|
|
14421
14505
|
const parts = [context.strategyName, context.exchangeName];
|
|
14422
14506
|
if (context.frameName)
|
|
14423
14507
|
parts.push(context.frameName);
|
|
@@ -14449,16 +14533,16 @@ class StrategyCoreService {
|
|
|
14449
14533
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14450
14534
|
* @returns Promise that resolves when validation is complete
|
|
14451
14535
|
*/
|
|
14452
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
14453
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14536
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$r(context), async (context) => {
|
|
14537
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
14454
14538
|
context,
|
|
14455
14539
|
});
|
|
14456
14540
|
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
14457
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$
|
|
14458
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$
|
|
14459
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$
|
|
14460
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14461
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14541
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$2);
|
|
14542
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$2);
|
|
14543
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$2);
|
|
14544
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2);
|
|
14545
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2));
|
|
14462
14546
|
});
|
|
14463
14547
|
/**
|
|
14464
14548
|
* Retrieves the currently active pending signal for the symbol.
|
|
@@ -15394,6 +15478,38 @@ class StrategyCoreService {
|
|
|
15394
15478
|
await this.validate(context);
|
|
15395
15479
|
return await this.strategyConnectionService.getPositionCountdownMinutes(backtest, symbol, context);
|
|
15396
15480
|
};
|
|
15481
|
+
/**
|
|
15482
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
15483
|
+
*
|
|
15484
|
+
* @param backtest - Whether running in backtest mode
|
|
15485
|
+
* @param symbol - Trading pair symbol
|
|
15486
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15487
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
15488
|
+
*/
|
|
15489
|
+
this.getPositionActiveMinutes = async (backtest, symbol, context) => {
|
|
15490
|
+
this.loggerService.log("strategyCoreService getPositionActiveMinutes", {
|
|
15491
|
+
symbol,
|
|
15492
|
+
context,
|
|
15493
|
+
});
|
|
15494
|
+
await this.validate(context);
|
|
15495
|
+
return await this.strategyConnectionService.getPositionActiveMinutes(backtest, symbol, context);
|
|
15496
|
+
};
|
|
15497
|
+
/**
|
|
15498
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
15499
|
+
*
|
|
15500
|
+
* @param backtest - Whether running in backtest mode
|
|
15501
|
+
* @param symbol - Trading pair symbol
|
|
15502
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15503
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
15504
|
+
*/
|
|
15505
|
+
this.getPositionWaitingMinutes = async (backtest, symbol, context) => {
|
|
15506
|
+
this.loggerService.log("strategyCoreService getPositionWaitingMinutes", {
|
|
15507
|
+
symbol,
|
|
15508
|
+
context,
|
|
15509
|
+
});
|
|
15510
|
+
await this.validate(context);
|
|
15511
|
+
return await this.strategyConnectionService.getPositionWaitingMinutes(backtest, symbol, context);
|
|
15512
|
+
};
|
|
15397
15513
|
/**
|
|
15398
15514
|
* Returns the best price reached in the profit direction during this position's life.
|
|
15399
15515
|
*
|
|
@@ -15787,7 +15903,7 @@ class SizingGlobalService {
|
|
|
15787
15903
|
* @param context - Context with riskName, exchangeName, frameName
|
|
15788
15904
|
* @returns Unique string key for memoization
|
|
15789
15905
|
*/
|
|
15790
|
-
const CREATE_KEY_FN$
|
|
15906
|
+
const CREATE_KEY_FN$q = (context) => {
|
|
15791
15907
|
const parts = [context.riskName, context.exchangeName];
|
|
15792
15908
|
if (context.frameName)
|
|
15793
15909
|
parts.push(context.frameName);
|
|
@@ -15813,7 +15929,7 @@ class RiskGlobalService {
|
|
|
15813
15929
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
15814
15930
|
* @returns Promise that resolves when validation is complete
|
|
15815
15931
|
*/
|
|
15816
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
15932
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$q(context), async (context) => {
|
|
15817
15933
|
this.loggerService.log("riskGlobalService validate", {
|
|
15818
15934
|
context,
|
|
15819
15935
|
});
|
|
@@ -15884,14 +16000,14 @@ class RiskGlobalService {
|
|
|
15884
16000
|
}
|
|
15885
16001
|
}
|
|
15886
16002
|
|
|
15887
|
-
const METHOD_NAME_VALIDATE = "actionCoreService validate";
|
|
16003
|
+
const METHOD_NAME_VALIDATE$1 = "actionCoreService validate";
|
|
15888
16004
|
/**
|
|
15889
16005
|
* Creates a unique key for memoizing validate calls.
|
|
15890
16006
|
* Key format: "strategyName:exchangeName:frameName"
|
|
15891
16007
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15892
16008
|
* @returns Unique string key for memoization
|
|
15893
16009
|
*/
|
|
15894
|
-
const CREATE_KEY_FN$
|
|
16010
|
+
const CREATE_KEY_FN$p = (context) => {
|
|
15895
16011
|
const parts = [context.strategyName, context.exchangeName];
|
|
15896
16012
|
if (context.frameName)
|
|
15897
16013
|
parts.push(context.frameName);
|
|
@@ -15935,17 +16051,17 @@ class ActionCoreService {
|
|
|
15935
16051
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
15936
16052
|
* @returns Promise that resolves when all validations complete
|
|
15937
16053
|
*/
|
|
15938
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
15939
|
-
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
16054
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$p(context), async (context) => {
|
|
16055
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
15940
16056
|
context,
|
|
15941
16057
|
});
|
|
15942
16058
|
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
15943
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
15944
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
15945
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
15946
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
15947
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
15948
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
16059
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$1);
|
|
16060
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$1);
|
|
16061
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$1);
|
|
16062
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1);
|
|
16063
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1));
|
|
16064
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$1));
|
|
15949
16065
|
});
|
|
15950
16066
|
/**
|
|
15951
16067
|
* Initializes all ClientAction instances for the strategy.
|
|
@@ -20978,7 +21094,7 @@ const ReportWriter = new ReportWriterAdapter();
|
|
|
20978
21094
|
* @param backtest - Whether running in backtest mode
|
|
20979
21095
|
* @returns Unique string key for memoization
|
|
20980
21096
|
*/
|
|
20981
|
-
const CREATE_KEY_FN$
|
|
21097
|
+
const CREATE_KEY_FN$o = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
20982
21098
|
const parts = [symbol, strategyName, exchangeName];
|
|
20983
21099
|
if (frameName)
|
|
20984
21100
|
parts.push(frameName);
|
|
@@ -21224,7 +21340,7 @@ class BacktestMarkdownService {
|
|
|
21224
21340
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21225
21341
|
* Each combination gets its own isolated storage instance.
|
|
21226
21342
|
*/
|
|
21227
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21343
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$o(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$a(symbol, strategyName, exchangeName, frameName));
|
|
21228
21344
|
/**
|
|
21229
21345
|
* Processes tick events and accumulates closed signals.
|
|
21230
21346
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -21381,7 +21497,7 @@ class BacktestMarkdownService {
|
|
|
21381
21497
|
payload,
|
|
21382
21498
|
});
|
|
21383
21499
|
if (payload) {
|
|
21384
|
-
const key = CREATE_KEY_FN$
|
|
21500
|
+
const key = CREATE_KEY_FN$o(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
21385
21501
|
this.getStorage.clear(key);
|
|
21386
21502
|
}
|
|
21387
21503
|
else {
|
|
@@ -21443,7 +21559,7 @@ class BacktestMarkdownService {
|
|
|
21443
21559
|
* @param backtest - Whether running in backtest mode
|
|
21444
21560
|
* @returns Unique string key for memoization
|
|
21445
21561
|
*/
|
|
21446
|
-
const CREATE_KEY_FN$
|
|
21562
|
+
const CREATE_KEY_FN$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21447
21563
|
const parts = [symbol, strategyName, exchangeName];
|
|
21448
21564
|
if (frameName)
|
|
21449
21565
|
parts.push(frameName);
|
|
@@ -21938,7 +22054,7 @@ class LiveMarkdownService {
|
|
|
21938
22054
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21939
22055
|
* Each combination gets its own isolated storage instance.
|
|
21940
22056
|
*/
|
|
21941
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22057
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$n(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$9(symbol, strategyName, exchangeName, frameName));
|
|
21942
22058
|
/**
|
|
21943
22059
|
* Subscribes to live signal emitter to receive tick events.
|
|
21944
22060
|
* Protected against multiple subscriptions.
|
|
@@ -22156,7 +22272,7 @@ class LiveMarkdownService {
|
|
|
22156
22272
|
payload,
|
|
22157
22273
|
});
|
|
22158
22274
|
if (payload) {
|
|
22159
|
-
const key = CREATE_KEY_FN$
|
|
22275
|
+
const key = CREATE_KEY_FN$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22160
22276
|
this.getStorage.clear(key);
|
|
22161
22277
|
}
|
|
22162
22278
|
else {
|
|
@@ -22176,7 +22292,7 @@ class LiveMarkdownService {
|
|
|
22176
22292
|
* @param backtest - Whether running in backtest mode
|
|
22177
22293
|
* @returns Unique string key for memoization
|
|
22178
22294
|
*/
|
|
22179
|
-
const CREATE_KEY_FN$
|
|
22295
|
+
const CREATE_KEY_FN$m = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22180
22296
|
const parts = [symbol, strategyName, exchangeName];
|
|
22181
22297
|
if (frameName)
|
|
22182
22298
|
parts.push(frameName);
|
|
@@ -22465,7 +22581,7 @@ class ScheduleMarkdownService {
|
|
|
22465
22581
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22466
22582
|
* Each combination gets its own isolated storage instance.
|
|
22467
22583
|
*/
|
|
22468
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22584
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$m(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$8(symbol, strategyName, exchangeName, frameName));
|
|
22469
22585
|
/**
|
|
22470
22586
|
* Subscribes to signal emitter to receive scheduled signal events.
|
|
22471
22587
|
* Protected against multiple subscriptions.
|
|
@@ -22668,7 +22784,7 @@ class ScheduleMarkdownService {
|
|
|
22668
22784
|
payload,
|
|
22669
22785
|
});
|
|
22670
22786
|
if (payload) {
|
|
22671
|
-
const key = CREATE_KEY_FN$
|
|
22787
|
+
const key = CREATE_KEY_FN$m(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22672
22788
|
this.getStorage.clear(key);
|
|
22673
22789
|
}
|
|
22674
22790
|
else {
|
|
@@ -22688,7 +22804,7 @@ class ScheduleMarkdownService {
|
|
|
22688
22804
|
* @param backtest - Whether running in backtest mode
|
|
22689
22805
|
* @returns Unique string key for memoization
|
|
22690
22806
|
*/
|
|
22691
|
-
const CREATE_KEY_FN$
|
|
22807
|
+
const CREATE_KEY_FN$l = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22692
22808
|
const parts = [symbol, strategyName, exchangeName];
|
|
22693
22809
|
if (frameName)
|
|
22694
22810
|
parts.push(frameName);
|
|
@@ -22933,7 +23049,7 @@ class PerformanceMarkdownService {
|
|
|
22933
23049
|
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22934
23050
|
* Each combination gets its own isolated storage instance.
|
|
22935
23051
|
*/
|
|
22936
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
23052
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$l(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new PerformanceStorage(symbol, strategyName, exchangeName, frameName));
|
|
22937
23053
|
/**
|
|
22938
23054
|
* Subscribes to performance emitter to receive performance events.
|
|
22939
23055
|
* Protected against multiple subscriptions.
|
|
@@ -23100,7 +23216,7 @@ class PerformanceMarkdownService {
|
|
|
23100
23216
|
payload,
|
|
23101
23217
|
});
|
|
23102
23218
|
if (payload) {
|
|
23103
|
-
const key = CREATE_KEY_FN$
|
|
23219
|
+
const key = CREATE_KEY_FN$l(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
23104
23220
|
this.getStorage.clear(key);
|
|
23105
23221
|
}
|
|
23106
23222
|
else {
|
|
@@ -23579,7 +23695,7 @@ class WalkerMarkdownService {
|
|
|
23579
23695
|
* @param backtest - Whether running in backtest mode
|
|
23580
23696
|
* @returns Unique string key for memoization
|
|
23581
23697
|
*/
|
|
23582
|
-
const CREATE_KEY_FN$
|
|
23698
|
+
const CREATE_KEY_FN$k = (exchangeName, frameName, backtest) => {
|
|
23583
23699
|
const parts = [exchangeName];
|
|
23584
23700
|
if (frameName)
|
|
23585
23701
|
parts.push(frameName);
|
|
@@ -24026,7 +24142,7 @@ class HeatMarkdownService {
|
|
|
24026
24142
|
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
24027
24143
|
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
24028
24144
|
*/
|
|
24029
|
-
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
24145
|
+
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$k(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
|
|
24030
24146
|
/**
|
|
24031
24147
|
* Subscribes to signal emitter to receive tick events.
|
|
24032
24148
|
* Protected against multiple subscriptions.
|
|
@@ -24244,7 +24360,7 @@ class HeatMarkdownService {
|
|
|
24244
24360
|
payload,
|
|
24245
24361
|
});
|
|
24246
24362
|
if (payload) {
|
|
24247
|
-
const key = CREATE_KEY_FN$
|
|
24363
|
+
const key = CREATE_KEY_FN$k(payload.exchangeName, payload.frameName, payload.backtest);
|
|
24248
24364
|
this.getStorage.clear(key);
|
|
24249
24365
|
}
|
|
24250
24366
|
else {
|
|
@@ -25275,7 +25391,7 @@ class ClientPartial {
|
|
|
25275
25391
|
* @param backtest - Whether running in backtest mode
|
|
25276
25392
|
* @returns Unique string key for memoization
|
|
25277
25393
|
*/
|
|
25278
|
-
const CREATE_KEY_FN$
|
|
25394
|
+
const CREATE_KEY_FN$j = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
25279
25395
|
/**
|
|
25280
25396
|
* Creates a callback function for emitting profit events to partialProfitSubject.
|
|
25281
25397
|
*
|
|
@@ -25397,7 +25513,7 @@ class PartialConnectionService {
|
|
|
25397
25513
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
25398
25514
|
* Value: ClientPartial instance with logger and event emitters
|
|
25399
25515
|
*/
|
|
25400
|
-
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
25516
|
+
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$j(signalId, backtest), (signalId, backtest) => {
|
|
25401
25517
|
return new ClientPartial({
|
|
25402
25518
|
signalId,
|
|
25403
25519
|
logger: this.loggerService,
|
|
@@ -25487,7 +25603,7 @@ class PartialConnectionService {
|
|
|
25487
25603
|
const partial = this.getPartial(data.id, backtest);
|
|
25488
25604
|
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
25489
25605
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
25490
|
-
const key = CREATE_KEY_FN$
|
|
25606
|
+
const key = CREATE_KEY_FN$j(data.id, backtest);
|
|
25491
25607
|
this.getPartial.clear(key);
|
|
25492
25608
|
};
|
|
25493
25609
|
}
|
|
@@ -25503,7 +25619,7 @@ class PartialConnectionService {
|
|
|
25503
25619
|
* @param backtest - Whether running in backtest mode
|
|
25504
25620
|
* @returns Unique string key for memoization
|
|
25505
25621
|
*/
|
|
25506
|
-
const CREATE_KEY_FN$
|
|
25622
|
+
const CREATE_KEY_FN$i = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
25507
25623
|
const parts = [symbol, strategyName, exchangeName];
|
|
25508
25624
|
if (frameName)
|
|
25509
25625
|
parts.push(frameName);
|
|
@@ -25726,7 +25842,7 @@ class PartialMarkdownService {
|
|
|
25726
25842
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
25727
25843
|
* Each combination gets its own isolated storage instance.
|
|
25728
25844
|
*/
|
|
25729
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
25845
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$i(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$6(symbol, strategyName, exchangeName, frameName));
|
|
25730
25846
|
/**
|
|
25731
25847
|
* Subscribes to partial profit/loss signal emitters to receive events.
|
|
25732
25848
|
* Protected against multiple subscriptions.
|
|
@@ -25936,7 +26052,7 @@ class PartialMarkdownService {
|
|
|
25936
26052
|
payload,
|
|
25937
26053
|
});
|
|
25938
26054
|
if (payload) {
|
|
25939
|
-
const key = CREATE_KEY_FN$
|
|
26055
|
+
const key = CREATE_KEY_FN$i(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
25940
26056
|
this.getStorage.clear(key);
|
|
25941
26057
|
}
|
|
25942
26058
|
else {
|
|
@@ -25952,7 +26068,7 @@ class PartialMarkdownService {
|
|
|
25952
26068
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
25953
26069
|
* @returns Unique string key for memoization
|
|
25954
26070
|
*/
|
|
25955
|
-
const CREATE_KEY_FN$
|
|
26071
|
+
const CREATE_KEY_FN$h = (context) => {
|
|
25956
26072
|
const parts = [context.strategyName, context.exchangeName];
|
|
25957
26073
|
if (context.frameName)
|
|
25958
26074
|
parts.push(context.frameName);
|
|
@@ -26026,7 +26142,7 @@ class PartialGlobalService {
|
|
|
26026
26142
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
26027
26143
|
* @param methodName - Name of the calling method for error tracking
|
|
26028
26144
|
*/
|
|
26029
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
26145
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$h(context), (context, methodName) => {
|
|
26030
26146
|
this.loggerService.log("partialGlobalService validate", {
|
|
26031
26147
|
context,
|
|
26032
26148
|
methodName,
|
|
@@ -26481,7 +26597,7 @@ class ClientBreakeven {
|
|
|
26481
26597
|
* @param backtest - Whether running in backtest mode
|
|
26482
26598
|
* @returns Unique string key for memoization
|
|
26483
26599
|
*/
|
|
26484
|
-
const CREATE_KEY_FN$
|
|
26600
|
+
const CREATE_KEY_FN$g = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
26485
26601
|
/**
|
|
26486
26602
|
* Creates a callback function for emitting breakeven events to breakevenSubject.
|
|
26487
26603
|
*
|
|
@@ -26567,7 +26683,7 @@ class BreakevenConnectionService {
|
|
|
26567
26683
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
26568
26684
|
* Value: ClientBreakeven instance with logger and event emitter
|
|
26569
26685
|
*/
|
|
26570
|
-
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
26686
|
+
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$g(signalId, backtest), (signalId, backtest) => {
|
|
26571
26687
|
return new ClientBreakeven({
|
|
26572
26688
|
signalId,
|
|
26573
26689
|
logger: this.loggerService,
|
|
@@ -26628,7 +26744,7 @@ class BreakevenConnectionService {
|
|
|
26628
26744
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
26629
26745
|
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
26630
26746
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
26631
|
-
const key = CREATE_KEY_FN$
|
|
26747
|
+
const key = CREATE_KEY_FN$g(data.id, backtest);
|
|
26632
26748
|
this.getBreakeven.clear(key);
|
|
26633
26749
|
};
|
|
26634
26750
|
}
|
|
@@ -26644,7 +26760,7 @@ class BreakevenConnectionService {
|
|
|
26644
26760
|
* @param backtest - Whether running in backtest mode
|
|
26645
26761
|
* @returns Unique string key for memoization
|
|
26646
26762
|
*/
|
|
26647
|
-
const CREATE_KEY_FN$
|
|
26763
|
+
const CREATE_KEY_FN$f = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
26648
26764
|
const parts = [symbol, strategyName, exchangeName];
|
|
26649
26765
|
if (frameName)
|
|
26650
26766
|
parts.push(frameName);
|
|
@@ -26819,7 +26935,7 @@ class BreakevenMarkdownService {
|
|
|
26819
26935
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
26820
26936
|
* Each combination gets its own isolated storage instance.
|
|
26821
26937
|
*/
|
|
26822
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
26938
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$f(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$5(symbol, strategyName, exchangeName, frameName));
|
|
26823
26939
|
/**
|
|
26824
26940
|
* Subscribes to breakeven signal emitter to receive events.
|
|
26825
26941
|
* Protected against multiple subscriptions.
|
|
@@ -27008,7 +27124,7 @@ class BreakevenMarkdownService {
|
|
|
27008
27124
|
payload,
|
|
27009
27125
|
});
|
|
27010
27126
|
if (payload) {
|
|
27011
|
-
const key = CREATE_KEY_FN$
|
|
27127
|
+
const key = CREATE_KEY_FN$f(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27012
27128
|
this.getStorage.clear(key);
|
|
27013
27129
|
}
|
|
27014
27130
|
else {
|
|
@@ -27024,7 +27140,7 @@ class BreakevenMarkdownService {
|
|
|
27024
27140
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
27025
27141
|
* @returns Unique string key for memoization
|
|
27026
27142
|
*/
|
|
27027
|
-
const CREATE_KEY_FN$
|
|
27143
|
+
const CREATE_KEY_FN$e = (context) => {
|
|
27028
27144
|
const parts = [context.strategyName, context.exchangeName];
|
|
27029
27145
|
if (context.frameName)
|
|
27030
27146
|
parts.push(context.frameName);
|
|
@@ -27098,7 +27214,7 @@ class BreakevenGlobalService {
|
|
|
27098
27214
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
27099
27215
|
* @param methodName - Name of the calling method for error tracking
|
|
27100
27216
|
*/
|
|
27101
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
27217
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$e(context), (context, methodName) => {
|
|
27102
27218
|
this.loggerService.log("breakevenGlobalService validate", {
|
|
27103
27219
|
context,
|
|
27104
27220
|
methodName,
|
|
@@ -27319,7 +27435,7 @@ class ConfigValidationService {
|
|
|
27319
27435
|
* @param backtest - Whether running in backtest mode
|
|
27320
27436
|
* @returns Unique string key for memoization
|
|
27321
27437
|
*/
|
|
27322
|
-
const CREATE_KEY_FN$
|
|
27438
|
+
const CREATE_KEY_FN$d = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27323
27439
|
const parts = [symbol, strategyName, exchangeName];
|
|
27324
27440
|
if (frameName)
|
|
27325
27441
|
parts.push(frameName);
|
|
@@ -27486,7 +27602,7 @@ class RiskMarkdownService {
|
|
|
27486
27602
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27487
27603
|
* Each combination gets its own isolated storage instance.
|
|
27488
27604
|
*/
|
|
27489
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
27605
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$d(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$4(symbol, strategyName, exchangeName, frameName));
|
|
27490
27606
|
/**
|
|
27491
27607
|
* Subscribes to risk rejection emitter to receive rejection events.
|
|
27492
27608
|
* Protected against multiple subscriptions.
|
|
@@ -27675,7 +27791,7 @@ class RiskMarkdownService {
|
|
|
27675
27791
|
payload,
|
|
27676
27792
|
});
|
|
27677
27793
|
if (payload) {
|
|
27678
|
-
const key = CREATE_KEY_FN$
|
|
27794
|
+
const key = CREATE_KEY_FN$d(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27679
27795
|
this.getStorage.clear(key);
|
|
27680
27796
|
}
|
|
27681
27797
|
else {
|
|
@@ -30057,7 +30173,7 @@ class HighestProfitReportService {
|
|
|
30057
30173
|
* @returns Colon-separated key string for memoization
|
|
30058
30174
|
* @internal
|
|
30059
30175
|
*/
|
|
30060
|
-
const CREATE_KEY_FN$
|
|
30176
|
+
const CREATE_KEY_FN$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30061
30177
|
const parts = [symbol, strategyName, exchangeName];
|
|
30062
30178
|
if (frameName)
|
|
30063
30179
|
parts.push(frameName);
|
|
@@ -30299,7 +30415,7 @@ class StrategyMarkdownService {
|
|
|
30299
30415
|
*
|
|
30300
30416
|
* @internal
|
|
30301
30417
|
*/
|
|
30302
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
30418
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$c(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$3(symbol, strategyName, exchangeName, frameName));
|
|
30303
30419
|
/**
|
|
30304
30420
|
* Records a cancel-scheduled event when a scheduled signal is cancelled.
|
|
30305
30421
|
*
|
|
@@ -30873,7 +30989,7 @@ class StrategyMarkdownService {
|
|
|
30873
30989
|
this.clear = async (payload) => {
|
|
30874
30990
|
this.loggerService.log("strategyMarkdownService clear", { payload });
|
|
30875
30991
|
if (payload) {
|
|
30876
|
-
const key = CREATE_KEY_FN$
|
|
30992
|
+
const key = CREATE_KEY_FN$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
30877
30993
|
this.getStorage.clear(key);
|
|
30878
30994
|
}
|
|
30879
30995
|
else {
|
|
@@ -30981,7 +31097,7 @@ class StrategyMarkdownService {
|
|
|
30981
31097
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
30982
31098
|
* Key format: "symbol:strategyName:exchangeName[:frameName]:backtest|live"
|
|
30983
31099
|
*/
|
|
30984
|
-
const CREATE_KEY_FN$
|
|
31100
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30985
31101
|
const parts = [symbol, strategyName, exchangeName];
|
|
30986
31102
|
if (frameName)
|
|
30987
31103
|
parts.push(frameName);
|
|
@@ -31174,7 +31290,7 @@ let ReportStorage$2 = class ReportStorage {
|
|
|
31174
31290
|
class SyncMarkdownService {
|
|
31175
31291
|
constructor() {
|
|
31176
31292
|
this.loggerService = inject(TYPES.loggerService);
|
|
31177
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31293
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$2(symbol, strategyName, exchangeName, frameName, backtest));
|
|
31178
31294
|
/**
|
|
31179
31295
|
* Subscribes to `syncSubject` to start receiving `SignalSyncContract` events.
|
|
31180
31296
|
* Protected against multiple subscriptions via `singleshot` — subsequent calls
|
|
@@ -31370,7 +31486,7 @@ class SyncMarkdownService {
|
|
|
31370
31486
|
this.clear = async (payload) => {
|
|
31371
31487
|
this.loggerService.log("syncMarkdownService clear", { payload });
|
|
31372
31488
|
if (payload) {
|
|
31373
|
-
const key = CREATE_KEY_FN$
|
|
31489
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31374
31490
|
this.getStorage.clear(key);
|
|
31375
31491
|
}
|
|
31376
31492
|
else {
|
|
@@ -31383,7 +31499,7 @@ class SyncMarkdownService {
|
|
|
31383
31499
|
/**
|
|
31384
31500
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31385
31501
|
*/
|
|
31386
|
-
const CREATE_KEY_FN$
|
|
31502
|
+
const CREATE_KEY_FN$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31387
31503
|
const parts = [symbol, strategyName, exchangeName];
|
|
31388
31504
|
if (frameName)
|
|
31389
31505
|
parts.push(frameName);
|
|
@@ -31559,7 +31675,7 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
31559
31675
|
class HighestProfitMarkdownService {
|
|
31560
31676
|
constructor() {
|
|
31561
31677
|
this.loggerService = inject(TYPES.loggerService);
|
|
31562
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31678
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$1(symbol, strategyName, exchangeName, frameName));
|
|
31563
31679
|
/**
|
|
31564
31680
|
* Subscribes to `highestProfitSubject` to start receiving `HighestProfitContract`
|
|
31565
31681
|
* events. Protected against multiple subscriptions via `singleshot` — subsequent
|
|
@@ -31725,7 +31841,7 @@ class HighestProfitMarkdownService {
|
|
|
31725
31841
|
this.clear = async (payload) => {
|
|
31726
31842
|
this.loggerService.log("highestProfitMarkdownService clear", { payload });
|
|
31727
31843
|
if (payload) {
|
|
31728
|
-
const key = CREATE_KEY_FN$
|
|
31844
|
+
const key = CREATE_KEY_FN$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31729
31845
|
this.getStorage.clear(key);
|
|
31730
31846
|
}
|
|
31731
31847
|
else {
|
|
@@ -31747,7 +31863,7 @@ const LISTEN_TIMEOUT$1 = 120000;
|
|
|
31747
31863
|
* @param backtest - Whether running in backtest mode
|
|
31748
31864
|
* @returns Unique string key for memoization
|
|
31749
31865
|
*/
|
|
31750
|
-
const CREATE_KEY_FN$
|
|
31866
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31751
31867
|
const parts = [symbol, strategyName, exchangeName];
|
|
31752
31868
|
if (frameName)
|
|
31753
31869
|
parts.push(frameName);
|
|
@@ -31790,7 +31906,7 @@ class PriceMetaService {
|
|
|
31790
31906
|
* Each subject holds the latest currentPrice emitted by the strategy iterator for that key.
|
|
31791
31907
|
* Instances are cached until clear() is called.
|
|
31792
31908
|
*/
|
|
31793
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31909
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
31794
31910
|
/**
|
|
31795
31911
|
* Returns the current market price for the given symbol and context.
|
|
31796
31912
|
*
|
|
@@ -31819,10 +31935,10 @@ class PriceMetaService {
|
|
|
31819
31935
|
if (source.data) {
|
|
31820
31936
|
return source.data;
|
|
31821
31937
|
}
|
|
31822
|
-
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$
|
|
31938
|
+
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
31823
31939
|
const currentPrice = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT$1);
|
|
31824
31940
|
if (typeof currentPrice === "symbol") {
|
|
31825
|
-
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$
|
|
31941
|
+
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31826
31942
|
}
|
|
31827
31943
|
return currentPrice;
|
|
31828
31944
|
};
|
|
@@ -31864,7 +31980,7 @@ class PriceMetaService {
|
|
|
31864
31980
|
this.getSource.clear();
|
|
31865
31981
|
return;
|
|
31866
31982
|
}
|
|
31867
|
-
const key = CREATE_KEY_FN$
|
|
31983
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31868
31984
|
this.getSource.clear(key);
|
|
31869
31985
|
};
|
|
31870
31986
|
}
|
|
@@ -31882,7 +31998,7 @@ const LISTEN_TIMEOUT = 120000;
|
|
|
31882
31998
|
* @param backtest - Whether running in backtest mode
|
|
31883
31999
|
* @returns Unique string key for memoization
|
|
31884
32000
|
*/
|
|
31885
|
-
const CREATE_KEY_FN$
|
|
32001
|
+
const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31886
32002
|
const parts = [symbol, strategyName, exchangeName];
|
|
31887
32003
|
if (frameName)
|
|
31888
32004
|
parts.push(frameName);
|
|
@@ -31925,7 +32041,7 @@ class TimeMetaService {
|
|
|
31925
32041
|
* Each subject holds the latest createdAt timestamp emitted by the strategy iterator for that key.
|
|
31926
32042
|
* Instances are cached until clear() is called.
|
|
31927
32043
|
*/
|
|
31928
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32044
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
31929
32045
|
/**
|
|
31930
32046
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
31931
32047
|
*
|
|
@@ -31953,10 +32069,10 @@ class TimeMetaService {
|
|
|
31953
32069
|
if (source.data) {
|
|
31954
32070
|
return source.data;
|
|
31955
32071
|
}
|
|
31956
|
-
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$
|
|
32072
|
+
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
31957
32073
|
const timestamp = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT);
|
|
31958
32074
|
if (typeof timestamp === "symbol") {
|
|
31959
|
-
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$
|
|
32075
|
+
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31960
32076
|
}
|
|
31961
32077
|
return timestamp;
|
|
31962
32078
|
};
|
|
@@ -31998,7 +32114,7 @@ class TimeMetaService {
|
|
|
31998
32114
|
this.getSource.clear();
|
|
31999
32115
|
return;
|
|
32000
32116
|
}
|
|
32001
|
-
const key = CREATE_KEY_FN$
|
|
32117
|
+
const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32002
32118
|
this.getSource.clear(key);
|
|
32003
32119
|
};
|
|
32004
32120
|
}
|
|
@@ -32094,7 +32210,7 @@ class MaxDrawdownReportService {
|
|
|
32094
32210
|
/**
|
|
32095
32211
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
32096
32212
|
*/
|
|
32097
|
-
const CREATE_KEY_FN$
|
|
32213
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32098
32214
|
const parts = [symbol, strategyName, exchangeName];
|
|
32099
32215
|
if (frameName)
|
|
32100
32216
|
parts.push(frameName);
|
|
@@ -32218,7 +32334,7 @@ class ReportStorage {
|
|
|
32218
32334
|
class MaxDrawdownMarkdownService {
|
|
32219
32335
|
constructor() {
|
|
32220
32336
|
this.loggerService = inject(TYPES.loggerService);
|
|
32221
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32337
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage(symbol, strategyName, exchangeName, frameName));
|
|
32222
32338
|
/**
|
|
32223
32339
|
* Subscribes to `maxDrawdownSubject` to start receiving `MaxDrawdownContract`
|
|
32224
32340
|
* events. Protected against multiple subscriptions via `singleshot`.
|
|
@@ -32297,7 +32413,7 @@ class MaxDrawdownMarkdownService {
|
|
|
32297
32413
|
this.clear = async (payload) => {
|
|
32298
32414
|
this.loggerService.log("maxDrawdownMarkdownService clear", { payload });
|
|
32299
32415
|
if (payload) {
|
|
32300
|
-
const key = CREATE_KEY_FN$
|
|
32416
|
+
const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32301
32417
|
this.getStorage.clear(key);
|
|
32302
32418
|
}
|
|
32303
32419
|
else {
|
|
@@ -32307,6 +32423,125 @@ class MaxDrawdownMarkdownService {
|
|
|
32307
32423
|
}
|
|
32308
32424
|
}
|
|
32309
32425
|
|
|
32426
|
+
const METHOD_NAME_COMMIT_SIGNAL_NOTIFY = "notificationHelperService.commitSignalNotify";
|
|
32427
|
+
const METHOD_NAME_VALIDATE = "notificationHelperService.validate";
|
|
32428
|
+
/**
|
|
32429
|
+
* Creates a unique key for memoizing validate calls.
|
|
32430
|
+
* Key format: "strategyName:exchangeName:frameName"
|
|
32431
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
32432
|
+
* @returns Unique string key for memoization
|
|
32433
|
+
*/
|
|
32434
|
+
const CREATE_KEY_FN$6 = (context) => {
|
|
32435
|
+
const parts = [context.strategyName, context.exchangeName];
|
|
32436
|
+
if (context.frameName)
|
|
32437
|
+
parts.push(context.frameName);
|
|
32438
|
+
return parts.join(":");
|
|
32439
|
+
};
|
|
32440
|
+
/**
|
|
32441
|
+
* Helper service for emitting signal info notifications.
|
|
32442
|
+
*
|
|
32443
|
+
* Handles validation (memoized per context) and emission of `signal.info` events
|
|
32444
|
+
* via `signalNotifySubject`. Used internally by the framework action pipeline —
|
|
32445
|
+
* end users interact with this via `commitSignalNotify()` in `onActivePing` callbacks.
|
|
32446
|
+
*/
|
|
32447
|
+
class NotificationHelperService {
|
|
32448
|
+
constructor() {
|
|
32449
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
32450
|
+
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
32451
|
+
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
32452
|
+
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
32453
|
+
this.exchangeValidationService = inject(TYPES.exchangeValidationService);
|
|
32454
|
+
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
32455
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
32456
|
+
this.strategyCoreService = inject(TYPES.strategyCoreService);
|
|
32457
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
32458
|
+
/**
|
|
32459
|
+
* Validates strategy, exchange, frame, risk, and action schemas for the given context.
|
|
32460
|
+
*
|
|
32461
|
+
* Memoized per unique `"strategyName:exchangeName[:frameName]"` key — subsequent calls
|
|
32462
|
+
* with the same context are no-ops, so validation runs at most once per context.
|
|
32463
|
+
*
|
|
32464
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32465
|
+
* @throws {Error} If any registered schema fails validation
|
|
32466
|
+
*/
|
|
32467
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$6(context), async (context) => {
|
|
32468
|
+
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
32469
|
+
context,
|
|
32470
|
+
});
|
|
32471
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
32472
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
32473
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
32474
|
+
context.frameName &&
|
|
32475
|
+
this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
32476
|
+
riskName &&
|
|
32477
|
+
this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
32478
|
+
riskList &&
|
|
32479
|
+
riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
32480
|
+
actions &&
|
|
32481
|
+
actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
32482
|
+
});
|
|
32483
|
+
/**
|
|
32484
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
32485
|
+
*
|
|
32486
|
+
* Validates all schemas (via memoized `validate`), resolves the pending signal
|
|
32487
|
+
* for the given symbol, then emits a `SignalInfoContract` via `signalNotifySubject`,
|
|
32488
|
+
* which is routed to all registered `listenSignalNotify` callbacks and persisted
|
|
32489
|
+
* by `NotificationAdapter`.
|
|
32490
|
+
*
|
|
32491
|
+
* @param payload - Optional notification fields (notificationId, notificationNote)
|
|
32492
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
32493
|
+
* @param currentPrice - Market price at the time of the call
|
|
32494
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32495
|
+
* @param backtest - true when called during a backtest run
|
|
32496
|
+
*
|
|
32497
|
+
* @throws {Error} If no active pending signal is found for the given symbol
|
|
32498
|
+
*
|
|
32499
|
+
* @example
|
|
32500
|
+
* ```typescript
|
|
32501
|
+
* // Inside onActivePing callback:
|
|
32502
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
32503
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
32504
|
+
* notificationId: "msg-123",
|
|
32505
|
+
* });
|
|
32506
|
+
* ```
|
|
32507
|
+
*/
|
|
32508
|
+
this.commitSignalNotify = async (payload, symbol, currentPrice, context, backtest) => {
|
|
32509
|
+
this.loggerService.info(METHOD_NAME_COMMIT_SIGNAL_NOTIFY, {
|
|
32510
|
+
symbol,
|
|
32511
|
+
context,
|
|
32512
|
+
backtest,
|
|
32513
|
+
currentPrice,
|
|
32514
|
+
});
|
|
32515
|
+
this.validate(context);
|
|
32516
|
+
const pendingSignal = await this.strategyCoreService.getPendingSignal(backtest, symbol, currentPrice, {
|
|
32517
|
+
strategyName: context.strategyName,
|
|
32518
|
+
exchangeName: context.exchangeName,
|
|
32519
|
+
frameName: context.frameName,
|
|
32520
|
+
});
|
|
32521
|
+
if (!pendingSignal) {
|
|
32522
|
+
throw new Error(`SignalUtils notify No pending signal found symbol=${symbol} `);
|
|
32523
|
+
}
|
|
32524
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, {
|
|
32525
|
+
strategyName: context.strategyName,
|
|
32526
|
+
exchangeName: context.exchangeName,
|
|
32527
|
+
frameName: context.frameName,
|
|
32528
|
+
}, backtest);
|
|
32529
|
+
await signalNotifySubject.next({
|
|
32530
|
+
backtest,
|
|
32531
|
+
symbol,
|
|
32532
|
+
currentPrice,
|
|
32533
|
+
data: pendingSignal,
|
|
32534
|
+
exchangeName: context.exchangeName,
|
|
32535
|
+
strategyName: context.strategyName,
|
|
32536
|
+
frameName: context.frameName,
|
|
32537
|
+
note: payload.notificationNote || pendingSignal.note,
|
|
32538
|
+
notificationId: payload.notificationId,
|
|
32539
|
+
timestamp,
|
|
32540
|
+
});
|
|
32541
|
+
};
|
|
32542
|
+
}
|
|
32543
|
+
}
|
|
32544
|
+
|
|
32310
32545
|
{
|
|
32311
32546
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
32312
32547
|
}
|
|
@@ -32395,6 +32630,9 @@ class MaxDrawdownMarkdownService {
|
|
|
32395
32630
|
provide(TYPES.highestProfitReportService, () => new HighestProfitReportService());
|
|
32396
32631
|
provide(TYPES.maxDrawdownReportService, () => new MaxDrawdownReportService());
|
|
32397
32632
|
}
|
|
32633
|
+
{
|
|
32634
|
+
provide(TYPES.notificationHelperService, () => new NotificationHelperService());
|
|
32635
|
+
}
|
|
32398
32636
|
{
|
|
32399
32637
|
provide(TYPES.exchangeValidationService, () => new ExchangeValidationService());
|
|
32400
32638
|
provide(TYPES.strategyValidationService, () => new StrategyValidationService());
|
|
@@ -32495,6 +32733,9 @@ const reportServices = {
|
|
|
32495
32733
|
highestProfitReportService: inject(TYPES.highestProfitReportService),
|
|
32496
32734
|
maxDrawdownReportService: inject(TYPES.maxDrawdownReportService),
|
|
32497
32735
|
};
|
|
32736
|
+
const helperServices = {
|
|
32737
|
+
notificationHelperService: inject(TYPES.notificationHelperService),
|
|
32738
|
+
};
|
|
32498
32739
|
const validationServices = {
|
|
32499
32740
|
exchangeValidationService: inject(TYPES.exchangeValidationService),
|
|
32500
32741
|
strategyValidationService: inject(TYPES.strategyValidationService),
|
|
@@ -32520,6 +32761,7 @@ const backtest = {
|
|
|
32520
32761
|
...markdownServices,
|
|
32521
32762
|
...reportServices,
|
|
32522
32763
|
...validationServices,
|
|
32764
|
+
...helperServices,
|
|
32523
32765
|
};
|
|
32524
32766
|
init();
|
|
32525
32767
|
|
|
@@ -35414,6 +35656,8 @@ const GET_POSITION_PARTIALS_METHOD_NAME = "strategy.getPositionPartials";
|
|
|
35414
35656
|
const GET_POSITION_ENTRIES_METHOD_NAME = "strategy.getPositionEntries";
|
|
35415
35657
|
const GET_POSITION_ESTIMATE_MINUTES_METHOD_NAME = "strategy.getPositionEstimateMinutes";
|
|
35416
35658
|
const GET_POSITION_COUNTDOWN_MINUTES_METHOD_NAME = "strategy.getPositionCountdownMinutes";
|
|
35659
|
+
const GET_POSITION_ACTIVE_MINUTES_METHOD_NAME = "strategy.getPositionActiveMinutes";
|
|
35660
|
+
const GET_POSITION_WAITING_MINUTES_METHOD_NAME = "strategy.getPositionWaitingMinutes";
|
|
35417
35661
|
const GET_POSITION_HIGHEST_PROFIT_PRICE_METHOD_NAME = "strategy.getPositionHighestProfitPrice";
|
|
35418
35662
|
const GET_POSITION_HIGHEST_PROFIT_TIMESTAMP_METHOD_NAME = "strategy.getPositionHighestProfitTimestamp";
|
|
35419
35663
|
const GET_POSITION_HIGHEST_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionHighestPnlPercentage";
|
|
@@ -35436,6 +35680,7 @@ const GET_POSITION_ENTRY_OVERLAP_METHOD_NAME = "strategy.getPositionEntryOverlap
|
|
|
35436
35680
|
const GET_POSITION_PARTIAL_OVERLAP_METHOD_NAME = "strategy.getPositionPartialOverlap";
|
|
35437
35681
|
const HAS_NO_PENDING_SIGNAL_METHOD_NAME = "strategy.hasNoPendingSignal";
|
|
35438
35682
|
const HAS_NO_SCHEDULED_SIGNAL_METHOD_NAME = "strategy.hasNoScheduledSignal";
|
|
35683
|
+
const COMMIT_SIGNAL_NOTIFY_METHOD_NAME = "strategy.commitSignalNotify";
|
|
35439
35684
|
/**
|
|
35440
35685
|
* Cancels the scheduled signal without stopping the strategy.
|
|
35441
35686
|
*
|
|
@@ -36713,6 +36958,62 @@ async function getPositionCountdownMinutes(symbol) {
|
|
|
36713
36958
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36714
36959
|
return await backtest.strategyCoreService.getPositionCountdownMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36715
36960
|
}
|
|
36961
|
+
/**
|
|
36962
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
36963
|
+
*
|
|
36964
|
+
* Returns null if no pending signal exists.
|
|
36965
|
+
*
|
|
36966
|
+
* @param symbol - Trading pair symbol
|
|
36967
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
36968
|
+
*
|
|
36969
|
+
* @example
|
|
36970
|
+
* ```typescript
|
|
36971
|
+
* import { getPositionActiveMinutes } from "backtest-kit";
|
|
36972
|
+
*
|
|
36973
|
+
* const minutes = await getPositionActiveMinutes("BTCUSDT");
|
|
36974
|
+
* // e.g. 120 (position has been open for 2 hours)
|
|
36975
|
+
* ```
|
|
36976
|
+
*/
|
|
36977
|
+
async function getPositionActiveMinutes(symbol) {
|
|
36978
|
+
backtest.loggerService.info(GET_POSITION_ACTIVE_MINUTES_METHOD_NAME, { symbol });
|
|
36979
|
+
if (!ExecutionContextService.hasContext()) {
|
|
36980
|
+
throw new Error("getPositionActiveMinutes requires an execution context");
|
|
36981
|
+
}
|
|
36982
|
+
if (!MethodContextService.hasContext()) {
|
|
36983
|
+
throw new Error("getPositionActiveMinutes requires a method context");
|
|
36984
|
+
}
|
|
36985
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
36986
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36987
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36988
|
+
}
|
|
36989
|
+
/**
|
|
36990
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
36991
|
+
*
|
|
36992
|
+
* Returns null if no scheduled signal exists.
|
|
36993
|
+
*
|
|
36994
|
+
* @param symbol - Trading pair symbol
|
|
36995
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
36996
|
+
*
|
|
36997
|
+
* @example
|
|
36998
|
+
* ```typescript
|
|
36999
|
+
* import { getPositionWaitingMinutes } from "backtest-kit";
|
|
37000
|
+
*
|
|
37001
|
+
* const minutes = await getPositionWaitingMinutes("BTCUSDT");
|
|
37002
|
+
* // e.g. 15 (scheduled signal has been waiting 15 minutes for activation)
|
|
37003
|
+
* ```
|
|
37004
|
+
*/
|
|
37005
|
+
async function getPositionWaitingMinutes(symbol) {
|
|
37006
|
+
backtest.loggerService.info(GET_POSITION_WAITING_MINUTES_METHOD_NAME, { symbol });
|
|
37007
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37008
|
+
throw new Error("getPositionWaitingMinutes requires an execution context");
|
|
37009
|
+
}
|
|
37010
|
+
if (!MethodContextService.hasContext()) {
|
|
37011
|
+
throw new Error("getPositionWaitingMinutes requires a method context");
|
|
37012
|
+
}
|
|
37013
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37014
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37015
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
37016
|
+
}
|
|
36716
37017
|
/**
|
|
36717
37018
|
* Returns the best price reached in the profit direction during this position's life.
|
|
36718
37019
|
*
|
|
@@ -37400,6 +37701,50 @@ async function hasNoScheduledSignal(symbol) {
|
|
|
37400
37701
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37401
37702
|
return await functoolsKit.not(backtest.strategyCoreService.hasScheduledSignal(isBacktest, symbol, { exchangeName, frameName, strategyName }));
|
|
37402
37703
|
}
|
|
37704
|
+
/**
|
|
37705
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
37706
|
+
*
|
|
37707
|
+
* Broadcasts a user-defined informational note without affecting position state.
|
|
37708
|
+
* Useful for annotating strategy decisions, triggering external alerts, or logging
|
|
37709
|
+
* mid-position events (e.g. RSI crossing a threshold, volume spike detected).
|
|
37710
|
+
*
|
|
37711
|
+
* Automatically reads backtest/live mode from execution context.
|
|
37712
|
+
* Automatically reads strategyName, exchangeName, frameName from method context.
|
|
37713
|
+
* Automatically fetches current price via getAveragePrice.
|
|
37714
|
+
*
|
|
37715
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
37716
|
+
* @param payload - Optional notification fields
|
|
37717
|
+
* @param payload.notificationNote - Human-readable note. Falls back to signal.note if omitted.
|
|
37718
|
+
* @param payload.notificationId - Optional correlation ID for external systems (e.g. Telegram message ID).
|
|
37719
|
+
*
|
|
37720
|
+
* @throws {Error} If called outside an execution context
|
|
37721
|
+
* @throws {Error} If called outside a method context
|
|
37722
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
37723
|
+
*
|
|
37724
|
+
* @example
|
|
37725
|
+
* ```typescript
|
|
37726
|
+
* import { commitSignalNotify } from "backtest-kit";
|
|
37727
|
+
*
|
|
37728
|
+
* // Inside onActivePing callback:
|
|
37729
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
37730
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
37731
|
+
* notificationId: "msg-123",
|
|
37732
|
+
* });
|
|
37733
|
+
* ```
|
|
37734
|
+
*/
|
|
37735
|
+
async function commitSignalNotify(symbol, payload = {}) {
|
|
37736
|
+
backtest.loggerService.info(COMMIT_SIGNAL_NOTIFY_METHOD_NAME, { symbol, payload });
|
|
37737
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37738
|
+
throw new Error("commitSignalNotify requires an execution context");
|
|
37739
|
+
}
|
|
37740
|
+
if (!MethodContextService.hasContext()) {
|
|
37741
|
+
throw new Error("commitSignalNotify requires a method context");
|
|
37742
|
+
}
|
|
37743
|
+
const currentPrice = await getAveragePrice(symbol);
|
|
37744
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37745
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37746
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, { strategyName, exchangeName, frameName }, isBacktest);
|
|
37747
|
+
}
|
|
37403
37748
|
|
|
37404
37749
|
const STOP_STRATEGY_METHOD_NAME = "control.stopStrategy";
|
|
37405
37750
|
/**
|
|
@@ -37483,6 +37828,8 @@ const LISTEN_HIGHEST_PROFIT_METHOD_NAME = "event.listenHighestProfit";
|
|
|
37483
37828
|
const LISTEN_HIGHEST_PROFIT_ONCE_METHOD_NAME = "event.listenHighestProfitOnce";
|
|
37484
37829
|
const LISTEN_MAX_DRAWDOWN_METHOD_NAME = "event.listenMaxDrawdown";
|
|
37485
37830
|
const LISTEN_MAX_DRAWDOWN_ONCE_METHOD_NAME = "event.listenMaxDrawdownOnce";
|
|
37831
|
+
const LISTEN_SIGNAL_NOTIFY_METHOD_NAME = "event.listenSignalNotify";
|
|
37832
|
+
const LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME = "event.listenSignalNotifyOnce";
|
|
37486
37833
|
/**
|
|
37487
37834
|
* Subscribes to all signal events with queued async processing.
|
|
37488
37835
|
*
|
|
@@ -38874,6 +39221,46 @@ function listenMaxDrawdownOnce(filterFn, fn) {
|
|
|
38874
39221
|
};
|
|
38875
39222
|
return disposeFn = listenMaxDrawdown(wrappedFn);
|
|
38876
39223
|
}
|
|
39224
|
+
/**
|
|
39225
|
+
* Subscribes to signal info events with queued async processing.
|
|
39226
|
+
* Emits when a strategy calls commitSignalInfo() to broadcast a user-defined note for an open position.
|
|
39227
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
39228
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
39229
|
+
* @param fn - Callback function to handle signal info events
|
|
39230
|
+
* @return Unsubscribe function to stop listening to events
|
|
39231
|
+
*/
|
|
39232
|
+
function listenSignalNotify(fn) {
|
|
39233
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_METHOD_NAME);
|
|
39234
|
+
const wrappedFn = async (event) => {
|
|
39235
|
+
if (await backtest.strategyCoreService.hasPendingSignal(event.backtest, event.symbol, {
|
|
39236
|
+
strategyName: event.strategyName,
|
|
39237
|
+
exchangeName: event.exchangeName,
|
|
39238
|
+
frameName: event.frameName,
|
|
39239
|
+
})) {
|
|
39240
|
+
await fn(event);
|
|
39241
|
+
}
|
|
39242
|
+
};
|
|
39243
|
+
return signalNotifySubject.subscribe(functoolsKit.queued(wrappedFn));
|
|
39244
|
+
}
|
|
39245
|
+
/**
|
|
39246
|
+
* Subscribes to filtered signal info events with one-time execution.
|
|
39247
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
39248
|
+
* and automatically unsubscribes.
|
|
39249
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
39250
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
39251
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
39252
|
+
*/
|
|
39253
|
+
function listenSignalNotifyOnce(filterFn, fn) {
|
|
39254
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME);
|
|
39255
|
+
let disposeFn;
|
|
39256
|
+
const wrappedFn = async (event) => {
|
|
39257
|
+
if (filterFn(event)) {
|
|
39258
|
+
await fn(event);
|
|
39259
|
+
disposeFn && disposeFn();
|
|
39260
|
+
}
|
|
39261
|
+
};
|
|
39262
|
+
return disposeFn = listenSignalNotify(wrappedFn);
|
|
39263
|
+
}
|
|
38877
39264
|
|
|
38878
39265
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
38879
39266
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
@@ -38897,6 +39284,8 @@ const BACKTEST_METHOD_NAME_GET_POSITION_PARTIALS = "BacktestUtils.getPositionPar
|
|
|
38897
39284
|
const BACKTEST_METHOD_NAME_GET_POSITION_ENTRIES = "BacktestUtils.getPositionEntries";
|
|
38898
39285
|
const BACKTEST_METHOD_NAME_GET_POSITION_ESTIMATE_MINUTES = "BacktestUtils.getPositionEstimateMinutes";
|
|
38899
39286
|
const BACKTEST_METHOD_NAME_GET_POSITION_COUNTDOWN_MINUTES = "BacktestUtils.getPositionCountdownMinutes";
|
|
39287
|
+
const BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "BacktestUtils.getPositionActiveMinutes";
|
|
39288
|
+
const BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "BacktestUtils.getPositionWaitingMinutes";
|
|
38900
39289
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE = "BacktestUtils.getPositionHighestProfitPrice";
|
|
38901
39290
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "BacktestUtils.getPositionHighestProfitTimestamp";
|
|
38902
39291
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "BacktestUtils.getPositionHighestPnlPercentage";
|
|
@@ -38930,6 +39319,7 @@ const BACKTEST_METHOD_NAME_TRAILING_STOP_COST = "BacktestUtils.commitTrailingSto
|
|
|
38930
39319
|
const BACKTEST_METHOD_NAME_TRAILING_PROFIT_COST = "BacktestUtils.commitTrailingTakeCost";
|
|
38931
39320
|
const BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED = "Backtest.commitActivateScheduled";
|
|
38932
39321
|
const BACKTEST_METHOD_NAME_AVERAGE_BUY = "Backtest.commitAverageBuy";
|
|
39322
|
+
const BACKTEST_METHOD_NAME_SIGNAL_NOTIFY = "Backtest.commitSignalNotify";
|
|
38933
39323
|
const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
|
|
38934
39324
|
const BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "BacktestUtils.hasNoPendingSignal";
|
|
38935
39325
|
const BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "BacktestUtils.hasNoScheduledSignal";
|
|
@@ -39851,6 +40241,60 @@ class BacktestUtils {
|
|
|
39851
40241
|
}
|
|
39852
40242
|
return await backtest.strategyCoreService.getPositionCountdownMinutes(true, symbol, context);
|
|
39853
40243
|
};
|
|
40244
|
+
/**
|
|
40245
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
40246
|
+
*
|
|
40247
|
+
* Returns null if no pending signal exists.
|
|
40248
|
+
*
|
|
40249
|
+
* @param symbol - Trading pair symbol
|
|
40250
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40251
|
+
* @returns Active minutes (≥ 0), or null if no active position
|
|
40252
|
+
*/
|
|
40253
|
+
this.getPositionActiveMinutes = async (symbol, context) => {
|
|
40254
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, {
|
|
40255
|
+
symbol,
|
|
40256
|
+
context,
|
|
40257
|
+
});
|
|
40258
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40259
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40260
|
+
{
|
|
40261
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40262
|
+
riskName &&
|
|
40263
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40264
|
+
riskList &&
|
|
40265
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
40266
|
+
actions &&
|
|
40267
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
40268
|
+
}
|
|
40269
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(true, symbol, context);
|
|
40270
|
+
};
|
|
40271
|
+
/**
|
|
40272
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
40273
|
+
*
|
|
40274
|
+
* Returns null if no scheduled signal exists.
|
|
40275
|
+
*
|
|
40276
|
+
* @param symbol - Trading pair symbol
|
|
40277
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40278
|
+
* @returns Waiting minutes (≥ 0), or null if no scheduled signal
|
|
40279
|
+
*/
|
|
40280
|
+
this.getPositionWaitingMinutes = async (symbol, context) => {
|
|
40281
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES, {
|
|
40282
|
+
symbol,
|
|
40283
|
+
context,
|
|
40284
|
+
});
|
|
40285
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40286
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40287
|
+
{
|
|
40288
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40289
|
+
riskName &&
|
|
40290
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40291
|
+
riskList &&
|
|
40292
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
40293
|
+
actions &&
|
|
40294
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
40295
|
+
}
|
|
40296
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(true, symbol, context);
|
|
40297
|
+
};
|
|
39854
40298
|
/**
|
|
39855
40299
|
* Returns the best price reached in the profit direction during this position's life.
|
|
39856
40300
|
*
|
|
@@ -41285,6 +41729,33 @@ class BacktestUtils {
|
|
|
41285
41729
|
});
|
|
41286
41730
|
return await backtest.strategyCoreService.averageBuy(true, symbol, currentPrice, context, cost);
|
|
41287
41731
|
};
|
|
41732
|
+
/**
|
|
41733
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
41734
|
+
*
|
|
41735
|
+
* @param symbol - Trading pair symbol
|
|
41736
|
+
* @param currentPrice - Market price at the time of the call
|
|
41737
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
41738
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
41739
|
+
*
|
|
41740
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
41741
|
+
*
|
|
41742
|
+
* @example
|
|
41743
|
+
* ```typescript
|
|
41744
|
+
* await Backtest.commitSignalNotify("BTCUSDT", 42000, {
|
|
41745
|
+
* strategyName: "my-strategy",
|
|
41746
|
+
* exchangeName: "binance",
|
|
41747
|
+
* frameName: "1h"
|
|
41748
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
41749
|
+
* ```
|
|
41750
|
+
*/
|
|
41751
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
41752
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
41753
|
+
symbol,
|
|
41754
|
+
currentPrice,
|
|
41755
|
+
context,
|
|
41756
|
+
});
|
|
41757
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, context, true);
|
|
41758
|
+
};
|
|
41288
41759
|
/**
|
|
41289
41760
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
41290
41761
|
*
|
|
@@ -41465,6 +41936,8 @@ const LIVE_METHOD_NAME_GET_POSITION_PARTIALS = "LiveUtils.getPositionPartials";
|
|
|
41465
41936
|
const LIVE_METHOD_NAME_GET_POSITION_ENTRIES = "LiveUtils.getPositionEntries";
|
|
41466
41937
|
const LIVE_METHOD_NAME_GET_POSITION_ESTIMATE_MINUTES = "LiveUtils.getPositionEstimateMinutes";
|
|
41467
41938
|
const LIVE_METHOD_NAME_GET_POSITION_COUNTDOWN_MINUTES = "LiveUtils.getPositionCountdownMinutes";
|
|
41939
|
+
const LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "LiveUtils.getPositionActiveMinutes";
|
|
41940
|
+
const LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "LiveUtils.getPositionWaitingMinutes";
|
|
41468
41941
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE = "LiveUtils.getPositionHighestProfitPrice";
|
|
41469
41942
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "LiveUtils.getPositionHighestProfitTimestamp";
|
|
41470
41943
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "LiveUtils.getPositionHighestPnlPercentage";
|
|
@@ -41498,6 +41971,7 @@ const LIVE_METHOD_NAME_TRAILING_STOP_COST = "LiveUtils.commitTrailingStopCost";
|
|
|
41498
41971
|
const LIVE_METHOD_NAME_TRAILING_PROFIT_COST = "LiveUtils.commitTrailingTakeCost";
|
|
41499
41972
|
const LIVE_METHOD_NAME_ACTIVATE_SCHEDULED = "Live.commitActivateScheduled";
|
|
41500
41973
|
const LIVE_METHOD_NAME_AVERAGE_BUY = "Live.commitAverageBuy";
|
|
41974
|
+
const LIVE_METHOD_NAME_SIGNAL_NOTIFY = "Live.commitSignalNotify";
|
|
41501
41975
|
const LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "LiveUtils.hasNoPendingSignal";
|
|
41502
41976
|
const LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "LiveUtils.hasNoScheduledSignal";
|
|
41503
41977
|
/**
|
|
@@ -42498,6 +42972,68 @@ class LiveUtils {
|
|
|
42498
42972
|
frameName: "",
|
|
42499
42973
|
});
|
|
42500
42974
|
};
|
|
42975
|
+
/**
|
|
42976
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
42977
|
+
*
|
|
42978
|
+
* Returns null if no pending signal exists.
|
|
42979
|
+
*
|
|
42980
|
+
* @param symbol - Trading pair symbol
|
|
42981
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
42982
|
+
* @returns Active minutes (≥ 0), or null if no active position
|
|
42983
|
+
*/
|
|
42984
|
+
this.getPositionActiveMinutes = async (symbol, context) => {
|
|
42985
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, {
|
|
42986
|
+
symbol,
|
|
42987
|
+
context,
|
|
42988
|
+
});
|
|
42989
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42990
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42991
|
+
{
|
|
42992
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
42993
|
+
riskName &&
|
|
42994
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42995
|
+
riskList &&
|
|
42996
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
42997
|
+
actions &&
|
|
42998
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
42999
|
+
}
|
|
43000
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(false, symbol, {
|
|
43001
|
+
strategyName: context.strategyName,
|
|
43002
|
+
exchangeName: context.exchangeName,
|
|
43003
|
+
frameName: "",
|
|
43004
|
+
});
|
|
43005
|
+
};
|
|
43006
|
+
/**
|
|
43007
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
43008
|
+
*
|
|
43009
|
+
* Returns null if no scheduled signal exists.
|
|
43010
|
+
*
|
|
43011
|
+
* @param symbol - Trading pair symbol
|
|
43012
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
43013
|
+
* @returns Waiting minutes (≥ 0), or null if no scheduled signal
|
|
43014
|
+
*/
|
|
43015
|
+
this.getPositionWaitingMinutes = async (symbol, context) => {
|
|
43016
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES, {
|
|
43017
|
+
symbol,
|
|
43018
|
+
context,
|
|
43019
|
+
});
|
|
43020
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43021
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43022
|
+
{
|
|
43023
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
43024
|
+
riskName &&
|
|
43025
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43026
|
+
riskList &&
|
|
43027
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
43028
|
+
actions &&
|
|
43029
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
43030
|
+
}
|
|
43031
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(false, symbol, {
|
|
43032
|
+
strategyName: context.strategyName,
|
|
43033
|
+
exchangeName: context.exchangeName,
|
|
43034
|
+
frameName: "",
|
|
43035
|
+
});
|
|
43036
|
+
};
|
|
42501
43037
|
/**
|
|
42502
43038
|
* Returns the best price reached in the profit direction during this position's life.
|
|
42503
43039
|
*
|
|
@@ -44194,6 +44730,36 @@ class LiveUtils {
|
|
|
44194
44730
|
frameName: "",
|
|
44195
44731
|
}, cost);
|
|
44196
44732
|
};
|
|
44733
|
+
/**
|
|
44734
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
44735
|
+
*
|
|
44736
|
+
* @param symbol - Trading pair symbol
|
|
44737
|
+
* @param currentPrice - Market price at the time of the call
|
|
44738
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
44739
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
44740
|
+
*
|
|
44741
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
44742
|
+
*
|
|
44743
|
+
* @example
|
|
44744
|
+
* ```typescript
|
|
44745
|
+
* await Live.commitSignalNotify("BTCUSDT", 42000, {
|
|
44746
|
+
* strategyName: "my-strategy",
|
|
44747
|
+
* exchangeName: "binance",
|
|
44748
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
44749
|
+
* ```
|
|
44750
|
+
*/
|
|
44751
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
44752
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
44753
|
+
symbol,
|
|
44754
|
+
currentPrice,
|
|
44755
|
+
context,
|
|
44756
|
+
});
|
|
44757
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, {
|
|
44758
|
+
strategyName: context.strategyName,
|
|
44759
|
+
exchangeName: context.exchangeName,
|
|
44760
|
+
frameName: "",
|
|
44761
|
+
}, false);
|
|
44762
|
+
};
|
|
44197
44763
|
/**
|
|
44198
44764
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
44199
44765
|
*
|
|
@@ -47921,7 +48487,7 @@ const LOGGER_SERVICE$2 = new LoggerService();
|
|
|
47921
48487
|
* Default configuration that enables all report services.
|
|
47922
48488
|
* Used when no specific configuration is provided to enable().
|
|
47923
48489
|
*/
|
|
47924
|
-
const WILDCARD_TARGET$
|
|
48490
|
+
const WILDCARD_TARGET$2 = {
|
|
47925
48491
|
backtest: true,
|
|
47926
48492
|
strategy: true,
|
|
47927
48493
|
breakeven: true,
|
|
@@ -47972,7 +48538,7 @@ class ReportUtils {
|
|
|
47972
48538
|
*
|
|
47973
48539
|
* @returns Cleanup function that unsubscribes from all enabled services
|
|
47974
48540
|
*/
|
|
47975
|
-
this.enable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, schedule = false, walker = false, strategy = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$
|
|
48541
|
+
this.enable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, schedule = false, walker = false, strategy = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$2) => {
|
|
47976
48542
|
LOGGER_SERVICE$2.debug(REPORT_UTILS_METHOD_NAME_ENABLE, {
|
|
47977
48543
|
backtest: bt,
|
|
47978
48544
|
breakeven,
|
|
@@ -48064,7 +48630,7 @@ class ReportUtils {
|
|
|
48064
48630
|
* Report.disable();
|
|
48065
48631
|
* ```
|
|
48066
48632
|
*/
|
|
48067
|
-
this.disable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, schedule = false, walker = false, strategy = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$
|
|
48633
|
+
this.disable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, schedule = false, walker = false, strategy = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$2) => {
|
|
48068
48634
|
LOGGER_SERVICE$2.debug(REPORT_UTILS_METHOD_NAME_DISABLE, {
|
|
48069
48635
|
backtest: bt,
|
|
48070
48636
|
breakeven,
|
|
@@ -48188,7 +48754,7 @@ const LOGGER_SERVICE$1 = new LoggerService();
|
|
|
48188
48754
|
* Default configuration that enables all markdown services.
|
|
48189
48755
|
* Used when no specific configuration is provided to `enable()`.
|
|
48190
48756
|
*/
|
|
48191
|
-
const WILDCARD_TARGET = {
|
|
48757
|
+
const WILDCARD_TARGET$1 = {
|
|
48192
48758
|
backtest: true,
|
|
48193
48759
|
breakeven: true,
|
|
48194
48760
|
heat: true,
|
|
@@ -48239,7 +48805,7 @@ class MarkdownUtils {
|
|
|
48239
48805
|
*
|
|
48240
48806
|
* @returns Cleanup function that unsubscribes from all enabled services
|
|
48241
48807
|
*/
|
|
48242
|
-
this.enable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, strategy = false, risk = false, schedule = false, walker = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET) => {
|
|
48808
|
+
this.enable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, strategy = false, risk = false, schedule = false, walker = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$1) => {
|
|
48243
48809
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_ENABLE, {
|
|
48244
48810
|
backtest: bt,
|
|
48245
48811
|
breakeven,
|
|
@@ -48333,7 +48899,7 @@ class MarkdownUtils {
|
|
|
48333
48899
|
* Markdown.disable();
|
|
48334
48900
|
* ```
|
|
48335
48901
|
*/
|
|
48336
|
-
this.disable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, strategy = false, schedule = false, walker = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET) => {
|
|
48902
|
+
this.disable = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, strategy = false, schedule = false, walker = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$1) => {
|
|
48337
48903
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_DISABLE, {
|
|
48338
48904
|
backtest: bt,
|
|
48339
48905
|
breakeven,
|
|
@@ -48388,6 +48954,87 @@ class MarkdownUtils {
|
|
|
48388
48954
|
backtest.maxDrawdownMarkdownService.unsubscribe();
|
|
48389
48955
|
}
|
|
48390
48956
|
};
|
|
48957
|
+
/**
|
|
48958
|
+
* Clears markdown report data selectively.
|
|
48959
|
+
*
|
|
48960
|
+
* Clears accumulated data for specified markdown services without unsubscribing.
|
|
48961
|
+
* Use this method to reset report data for specific services while keeping them active.
|
|
48962
|
+
*
|
|
48963
|
+
* Each cleared service will:
|
|
48964
|
+
* - Clear accumulated data for all reports
|
|
48965
|
+
* - Start fresh with new data for future events
|
|
48966
|
+
* - Not affect event subscriptions or report generation status
|
|
48967
|
+
*
|
|
48968
|
+
* @param config - Service configuration object specifying which services to clear. Defaults to clearing all services.
|
|
48969
|
+
* @param config.backtest - Clear backtest result report data
|
|
48970
|
+
* @param config.breakeven - Clear breakeven event tracking data
|
|
48971
|
+
* @param config.partial - Clear partial profit/loss event tracking data
|
|
48972
|
+
* @param config.heat - Clear portfolio heatmap analysis data
|
|
48973
|
+
* @param config.walker - Clear walker strategy comparison report data
|
|
48974
|
+
* @param config.performance - Clear performance bottleneck analysis data
|
|
48975
|
+
* @param config.risk - Clear risk rejection tracking data
|
|
48976
|
+
* @param config.schedule - Clear scheduled signal tracking data
|
|
48977
|
+
* @param config.live - Clear live trading event report data
|
|
48978
|
+
* @param config.strategy - Clear strategy report data
|
|
48979
|
+
* @param config.sync - Clear sync report data
|
|
48980
|
+
* @param config.highest_profit - Clear highest profit report data
|
|
48981
|
+
* @param config.max_drawdown - Clear max drawdown report data
|
|
48982
|
+
*/
|
|
48983
|
+
this.clear = ({ backtest: bt = false, breakeven = false, heat = false, live = false, partial = false, performance = false, risk = false, strategy = false, schedule = false, walker = false, sync = false, highest_profit = false, max_drawdown = false, } = WILDCARD_TARGET$1) => {
|
|
48984
|
+
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_CLEAR, {
|
|
48985
|
+
backtest: bt,
|
|
48986
|
+
breakeven,
|
|
48987
|
+
heat,
|
|
48988
|
+
live,
|
|
48989
|
+
partial,
|
|
48990
|
+
performance,
|
|
48991
|
+
risk,
|
|
48992
|
+
strategy,
|
|
48993
|
+
schedule,
|
|
48994
|
+
walker,
|
|
48995
|
+
sync,
|
|
48996
|
+
highest_profit,
|
|
48997
|
+
});
|
|
48998
|
+
if (bt) {
|
|
48999
|
+
backtest.backtestMarkdownService.clear();
|
|
49000
|
+
}
|
|
49001
|
+
if (breakeven) {
|
|
49002
|
+
backtest.breakevenMarkdownService.clear();
|
|
49003
|
+
}
|
|
49004
|
+
if (heat) {
|
|
49005
|
+
backtest.heatMarkdownService.clear();
|
|
49006
|
+
}
|
|
49007
|
+
if (live) {
|
|
49008
|
+
backtest.liveMarkdownService.clear();
|
|
49009
|
+
}
|
|
49010
|
+
if (partial) {
|
|
49011
|
+
backtest.partialMarkdownService.clear();
|
|
49012
|
+
}
|
|
49013
|
+
if (performance) {
|
|
49014
|
+
backtest.performanceMarkdownService.clear();
|
|
49015
|
+
}
|
|
49016
|
+
if (risk) {
|
|
49017
|
+
backtest.riskMarkdownService.clear();
|
|
49018
|
+
}
|
|
49019
|
+
if (strategy) {
|
|
49020
|
+
backtest.strategyMarkdownService.clear();
|
|
49021
|
+
}
|
|
49022
|
+
if (schedule) {
|
|
49023
|
+
backtest.scheduleMarkdownService.clear();
|
|
49024
|
+
}
|
|
49025
|
+
if (walker) {
|
|
49026
|
+
backtest.walkerMarkdownService.clear();
|
|
49027
|
+
}
|
|
49028
|
+
if (sync) {
|
|
49029
|
+
backtest.syncMarkdownService.clear();
|
|
49030
|
+
}
|
|
49031
|
+
if (highest_profit) {
|
|
49032
|
+
backtest.highestProfitMarkdownService.clear();
|
|
49033
|
+
}
|
|
49034
|
+
if (max_drawdown) {
|
|
49035
|
+
backtest.maxDrawdownMarkdownService.clear();
|
|
49036
|
+
}
|
|
49037
|
+
};
|
|
48391
49038
|
}
|
|
48392
49039
|
}
|
|
48393
49040
|
/**
|
|
@@ -48430,15 +49077,6 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
48430
49077
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_USE_JSONL);
|
|
48431
49078
|
MarkdownWriter.useJsonl();
|
|
48432
49079
|
}
|
|
48433
|
-
/**
|
|
48434
|
-
* Clears the memoized storage cache.
|
|
48435
|
-
* Call this when process.cwd() changes between strategy iterations
|
|
48436
|
-
* so new storage instances are created with the updated base path.
|
|
48437
|
-
*/
|
|
48438
|
-
clear() {
|
|
48439
|
-
LOGGER_SERVICE$1.log(MARKDOWN_METHOD_NAME_CLEAR);
|
|
48440
|
-
MarkdownWriter.clear();
|
|
48441
|
-
}
|
|
48442
49080
|
/**
|
|
48443
49081
|
* Switches to a dummy markdown adapter that discards all writes.
|
|
48444
49082
|
* All future markdown writes will be no-ops.
|
|
@@ -49135,6 +49773,7 @@ const SUBJECT_ISOLATION_LIST = [
|
|
|
49135
49773
|
strategyCommitSubject,
|
|
49136
49774
|
syncSubject,
|
|
49137
49775
|
validationSubject,
|
|
49776
|
+
signalNotifySubject,
|
|
49138
49777
|
];
|
|
49139
49778
|
/**
|
|
49140
49779
|
* Creates a snapshot function for a given subject by clearing its internal
|
|
@@ -50753,6 +51392,8 @@ const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "ReflectUtils.
|
|
|
50753
51392
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "ReflectUtils.getPositionHighestPnlPercentage";
|
|
50754
51393
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST = "ReflectUtils.getPositionHighestPnlCost";
|
|
50755
51394
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN = "ReflectUtils.getPositionHighestProfitBreakeven";
|
|
51395
|
+
const REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "ReflectUtils.getPositionActiveMinutes";
|
|
51396
|
+
const REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "ReflectUtils.getPositionWaitingMinutes";
|
|
50756
51397
|
const REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES = "ReflectUtils.getPositionDrawdownMinutes";
|
|
50757
51398
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES = "ReflectUtils.getPositionHighestProfitMinutes";
|
|
50758
51399
|
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES = "ReflectUtils.getPositionMaxDrawdownMinutes";
|
|
@@ -51027,6 +51668,52 @@ class ReflectUtils {
|
|
|
51027
51668
|
}
|
|
51028
51669
|
return await backtest.strategyCoreService.getPositionHighestProfitBreakeven(backtest$1, symbol, context);
|
|
51029
51670
|
};
|
|
51671
|
+
/**
|
|
51672
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
51673
|
+
*
|
|
51674
|
+
* Returns null if no pending signal exists.
|
|
51675
|
+
*
|
|
51676
|
+
* @param symbol - Trading pair symbol
|
|
51677
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
51678
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
51679
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
51680
|
+
*/
|
|
51681
|
+
this.getPositionActiveMinutes = async (symbol, context, backtest$1 = false) => {
|
|
51682
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, { symbol, context });
|
|
51683
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51684
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51685
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51686
|
+
{
|
|
51687
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
51688
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51689
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
51690
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
51691
|
+
}
|
|
51692
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(backtest$1, symbol, context);
|
|
51693
|
+
};
|
|
51694
|
+
/**
|
|
51695
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
51696
|
+
*
|
|
51697
|
+
* Returns null if no scheduled signal exists.
|
|
51698
|
+
*
|
|
51699
|
+
* @param symbol - Trading pair symbol
|
|
51700
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
51701
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
51702
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
51703
|
+
*/
|
|
51704
|
+
this.getPositionWaitingMinutes = async (symbol, context, backtest$1 = false) => {
|
|
51705
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES, { symbol, context });
|
|
51706
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51707
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51708
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51709
|
+
{
|
|
51710
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
51711
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51712
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
51713
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
51714
|
+
}
|
|
51715
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(backtest$1, symbol, context);
|
|
51716
|
+
};
|
|
51030
51717
|
/**
|
|
51031
51718
|
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
51032
51719
|
*
|
|
@@ -53303,6 +53990,23 @@ const StorageLive = new StorageLiveAdapter();
|
|
|
53303
53990
|
*/
|
|
53304
53991
|
const StorageBacktest = new StorageBacktestAdapter();
|
|
53305
53992
|
|
|
53993
|
+
/**
|
|
53994
|
+
* Default configuration that enables all notification types.
|
|
53995
|
+
* Used when no specific configuration is provided to enable().
|
|
53996
|
+
*/
|
|
53997
|
+
const WILDCARD_TARGET = {
|
|
53998
|
+
signal: true,
|
|
53999
|
+
partial_profit: true,
|
|
54000
|
+
partial_loss: true,
|
|
54001
|
+
breakeven: true,
|
|
54002
|
+
strategy_commit: true,
|
|
54003
|
+
signal_sync: true,
|
|
54004
|
+
risk: true,
|
|
54005
|
+
info: true,
|
|
54006
|
+
common_error: true,
|
|
54007
|
+
critical_error: true,
|
|
54008
|
+
validation_error: true,
|
|
54009
|
+
};
|
|
53306
54010
|
/**
|
|
53307
54011
|
* Generates a unique key for notification identification.
|
|
53308
54012
|
* @returns Random string identifier
|
|
@@ -53980,7 +54684,44 @@ const CREATE_VALIDATION_ERROR_NOTIFICATION_FN = (error) => ({
|
|
|
53980
54684
|
message: functoolsKit.getErrorMessage(error),
|
|
53981
54685
|
backtest: false,
|
|
53982
54686
|
});
|
|
54687
|
+
/**
|
|
54688
|
+
* Creates a notification model for signal info events.
|
|
54689
|
+
* @param data - The signal info contract data
|
|
54690
|
+
* @returns NotificationModel for signal info event
|
|
54691
|
+
*/
|
|
54692
|
+
const CREATE_SIGNAL_INFO_NOTIFICATION_FN = (data) => ({
|
|
54693
|
+
type: "signal.info",
|
|
54694
|
+
id: CREATE_KEY_FN$2(),
|
|
54695
|
+
timestamp: data.timestamp,
|
|
54696
|
+
backtest: data.backtest,
|
|
54697
|
+
symbol: data.symbol,
|
|
54698
|
+
strategyName: data.strategyName,
|
|
54699
|
+
exchangeName: data.exchangeName,
|
|
54700
|
+
signalId: data.data.id,
|
|
54701
|
+
currentPrice: data.currentPrice,
|
|
54702
|
+
position: data.data.position,
|
|
54703
|
+
priceOpen: data.data.priceOpen,
|
|
54704
|
+
priceTakeProfit: data.data.priceTakeProfit,
|
|
54705
|
+
priceStopLoss: data.data.priceStopLoss,
|
|
54706
|
+
originalPriceTakeProfit: data.data.originalPriceTakeProfit,
|
|
54707
|
+
originalPriceStopLoss: data.data.originalPriceStopLoss,
|
|
54708
|
+
originalPriceOpen: data.data.originalPriceOpen,
|
|
54709
|
+
totalEntries: data.data.totalEntries,
|
|
54710
|
+
totalPartials: data.data.totalPartials,
|
|
54711
|
+
pnl: data.data.pnl,
|
|
54712
|
+
pnlPercentage: data.data.pnl.pnlPercentage,
|
|
54713
|
+
pnlPriceOpen: data.data.pnl.priceOpen,
|
|
54714
|
+
pnlPriceClose: data.data.pnl.priceClose,
|
|
54715
|
+
pnlCost: data.data.pnl.pnlCost,
|
|
54716
|
+
pnlEntries: data.data.pnl.pnlEntries,
|
|
54717
|
+
note: data.note,
|
|
54718
|
+
notificationId: data.notificationId,
|
|
54719
|
+
scheduledAt: data.data.scheduledAt,
|
|
54720
|
+
pendingAt: data.data.pendingAt,
|
|
54721
|
+
createdAt: data.timestamp,
|
|
54722
|
+
});
|
|
53983
54723
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryBacktestUtils.handleSignal";
|
|
54724
|
+
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryBacktestUtils.handleSignalNotify";
|
|
53984
54725
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryBacktestUtils.handlePartialProfit";
|
|
53985
54726
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryBacktestUtils.handlePartialLoss";
|
|
53986
54727
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryBacktestUtils.handleBreakeven";
|
|
@@ -53993,6 +54734,7 @@ const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_VALIDATION_ERROR = "Notifi
|
|
|
53993
54734
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_GET_DATA = "NotificationMemoryBacktestUtils.getData";
|
|
53994
54735
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_DISPOSE = "NotificationMemoryBacktestUtils.dispose";
|
|
53995
54736
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryLiveUtils.handleSignal";
|
|
54737
|
+
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryLiveUtils.handleSignalNotify";
|
|
53996
54738
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryLiveUtils.handlePartialProfit";
|
|
53997
54739
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryLiveUtils.handlePartialLoss";
|
|
53998
54740
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryLiveUtils.handleBreakeven";
|
|
@@ -54021,6 +54763,7 @@ const NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR = "NotificationLiveAdapter.cle
|
|
|
54021
54763
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistBacktestUtils.waitForInit";
|
|
54022
54764
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistBacktestUtils._updateNotifications";
|
|
54023
54765
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistBacktestUtils.handleSignal";
|
|
54766
|
+
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistBacktestUtils.handleSignalNotify";
|
|
54024
54767
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistBacktestUtils.handlePartialProfit";
|
|
54025
54768
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistBacktestUtils.handlePartialLoss";
|
|
54026
54769
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistBacktestUtils.handleBreakeven";
|
|
@@ -54035,6 +54778,7 @@ const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_DISPOSE = "NotificationPersistBa
|
|
|
54035
54778
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistLiveUtils.waitForInit";
|
|
54036
54779
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistLiveUtils._updateNotifications";
|
|
54037
54780
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistLiveUtils.handleSignal";
|
|
54781
|
+
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistLiveUtils.handleSignalNotify";
|
|
54038
54782
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistLiveUtils.handlePartialProfit";
|
|
54039
54783
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistLiveUtils.handlePartialLoss";
|
|
54040
54784
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistLiveUtils.handleBreakeven";
|
|
@@ -54077,6 +54821,12 @@ class NotificationMemoryBacktestUtils {
|
|
|
54077
54821
|
this._addNotification(notification);
|
|
54078
54822
|
}
|
|
54079
54823
|
};
|
|
54824
|
+
this.handleSignalNotify = async (data) => {
|
|
54825
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
54826
|
+
signalId: data.data.id,
|
|
54827
|
+
});
|
|
54828
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
54829
|
+
};
|
|
54080
54830
|
/**
|
|
54081
54831
|
* Handles partial profit availability event.
|
|
54082
54832
|
* @param data - The partial profit contract data
|
|
@@ -54221,6 +54971,8 @@ class NotificationDummyBacktestUtils {
|
|
|
54221
54971
|
*/
|
|
54222
54972
|
this.handleSignal = async () => {
|
|
54223
54973
|
};
|
|
54974
|
+
this.handleSignalNotify = async () => {
|
|
54975
|
+
};
|
|
54224
54976
|
/**
|
|
54225
54977
|
* No-op handler for partial profit event.
|
|
54226
54978
|
*/
|
|
@@ -54328,6 +55080,14 @@ class NotificationPersistBacktestUtils {
|
|
|
54328
55080
|
await this._updateNotifications();
|
|
54329
55081
|
}
|
|
54330
55082
|
};
|
|
55083
|
+
this.handleSignalNotify = async (data) => {
|
|
55084
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55085
|
+
signalId: data.data.id,
|
|
55086
|
+
});
|
|
55087
|
+
await this.waitForInit();
|
|
55088
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55089
|
+
await this._updateNotifications();
|
|
55090
|
+
};
|
|
54331
55091
|
/**
|
|
54332
55092
|
* Handles partial profit availability event.
|
|
54333
55093
|
* @param data - The partial profit contract data
|
|
@@ -54529,6 +55289,12 @@ class NotificationMemoryLiveUtils {
|
|
|
54529
55289
|
this._addNotification(notification);
|
|
54530
55290
|
}
|
|
54531
55291
|
};
|
|
55292
|
+
this.handleSignalNotify = async (data) => {
|
|
55293
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55294
|
+
signalId: data.data.id,
|
|
55295
|
+
});
|
|
55296
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55297
|
+
};
|
|
54532
55298
|
/**
|
|
54533
55299
|
* Handles partial profit availability event.
|
|
54534
55300
|
* @param data - The partial profit contract data
|
|
@@ -54673,6 +55439,8 @@ class NotificationDummyLiveUtils {
|
|
|
54673
55439
|
*/
|
|
54674
55440
|
this.handleSignal = async () => {
|
|
54675
55441
|
};
|
|
55442
|
+
this.handleSignalNotify = async () => {
|
|
55443
|
+
};
|
|
54676
55444
|
/**
|
|
54677
55445
|
* No-op handler for partial profit event.
|
|
54678
55446
|
*/
|
|
@@ -54781,6 +55549,14 @@ class NotificationPersistLiveUtils {
|
|
|
54781
55549
|
await this._updateNotifications();
|
|
54782
55550
|
}
|
|
54783
55551
|
};
|
|
55552
|
+
this.handleSignalNotify = async (data) => {
|
|
55553
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55554
|
+
signalId: data.data.id,
|
|
55555
|
+
});
|
|
55556
|
+
await this.waitForInit();
|
|
55557
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55558
|
+
await this._updateNotifications();
|
|
55559
|
+
};
|
|
54784
55560
|
/**
|
|
54785
55561
|
* Handles partial profit availability event.
|
|
54786
55562
|
* @param data - The partial profit contract data
|
|
@@ -54974,6 +55750,9 @@ class NotificationBacktestAdapter {
|
|
|
54974
55750
|
this.handleSignal = async (data) => {
|
|
54975
55751
|
return await this._notificationBacktestUtils.handleSignal(data);
|
|
54976
55752
|
};
|
|
55753
|
+
this.handleSignalNotify = async (data) => {
|
|
55754
|
+
return await this._notificationBacktestUtils.handleSignalNotify(data);
|
|
55755
|
+
};
|
|
54977
55756
|
/**
|
|
54978
55757
|
* Handles partial profit availability event.
|
|
54979
55758
|
* Proxies call to the underlying notification adapter.
|
|
@@ -55129,6 +55908,9 @@ class NotificationLiveAdapter {
|
|
|
55129
55908
|
this.handleSignal = async (data) => {
|
|
55130
55909
|
return await this._notificationLiveUtils.handleSignal(data);
|
|
55131
55910
|
};
|
|
55911
|
+
this.handleSignalNotify = async (data) => {
|
|
55912
|
+
return await this._notificationLiveUtils.handleSignalNotify(data);
|
|
55913
|
+
};
|
|
55132
55914
|
/**
|
|
55133
55915
|
* Handles partial profit availability event.
|
|
55134
55916
|
* Proxies call to the underlying notification adapter.
|
|
@@ -55280,59 +56062,153 @@ class NotificationAdapter {
|
|
|
55280
56062
|
*
|
|
55281
56063
|
* @returns Cleanup function that unsubscribes from all emitters
|
|
55282
56064
|
*/
|
|
55283
|
-
this.enable = functoolsKit.singleshot(() => {
|
|
56065
|
+
this.enable = functoolsKit.singleshot(({ signal = false, info = false, partial_profit = false, partial_loss = false, breakeven = false, strategy_commit = false, signal_sync = false, risk = false, common_error = false, critical_error = false, validation_error = false, } = WILDCARD_TARGET) => {
|
|
55284
56066
|
backtest.loggerService.info(NOTIFICATION_ADAPTER_METHOD_NAME_ENABLE);
|
|
55285
56067
|
let unLive;
|
|
55286
56068
|
let unBacktest;
|
|
55287
56069
|
{
|
|
55288
|
-
const unBacktestSignal = signalBacktestEmitter.subscribe((data) =>
|
|
56070
|
+
const unBacktestSignal = signalBacktestEmitter.subscribe(async (data) => {
|
|
56071
|
+
if (signal) {
|
|
56072
|
+
await NotificationBacktest.handleSignal(data);
|
|
56073
|
+
}
|
|
56074
|
+
});
|
|
55289
56075
|
const unBacktestPartialProfit = partialProfitSubject
|
|
55290
56076
|
.filter(({ backtest }) => backtest)
|
|
55291
|
-
.connect((data) =>
|
|
56077
|
+
.connect(async (data) => {
|
|
56078
|
+
if (partial_profit) {
|
|
56079
|
+
await NotificationBacktest.handlePartialProfit(data);
|
|
56080
|
+
}
|
|
56081
|
+
});
|
|
55292
56082
|
const unBacktestPartialLoss = partialLossSubject
|
|
55293
56083
|
.filter(({ backtest }) => backtest)
|
|
55294
|
-
.connect((data) =>
|
|
56084
|
+
.connect(async (data) => {
|
|
56085
|
+
if (partial_loss) {
|
|
56086
|
+
await NotificationBacktest.handlePartialLoss(data);
|
|
56087
|
+
}
|
|
56088
|
+
});
|
|
55295
56089
|
const unBacktestBreakeven = breakevenSubject
|
|
55296
56090
|
.filter(({ backtest }) => backtest)
|
|
55297
|
-
.connect((data) =>
|
|
56091
|
+
.connect(async (data) => {
|
|
56092
|
+
if (breakeven) {
|
|
56093
|
+
await NotificationBacktest.handleBreakeven(data);
|
|
56094
|
+
}
|
|
56095
|
+
});
|
|
55298
56096
|
const unBacktestStrategyCommit = strategyCommitSubject
|
|
55299
56097
|
.filter(({ backtest }) => backtest)
|
|
55300
|
-
.connect((data) =>
|
|
56098
|
+
.connect(async (data) => {
|
|
56099
|
+
if (strategy_commit) {
|
|
56100
|
+
await NotificationBacktest.handleStrategyCommit(data);
|
|
56101
|
+
}
|
|
56102
|
+
});
|
|
55301
56103
|
const unBacktestSync = syncSubject
|
|
55302
56104
|
.filter(({ backtest }) => backtest)
|
|
55303
|
-
.connect((data) =>
|
|
56105
|
+
.connect(async (data) => {
|
|
56106
|
+
if (signal_sync) {
|
|
56107
|
+
await NotificationBacktest.handleSync(data);
|
|
56108
|
+
}
|
|
56109
|
+
});
|
|
55304
56110
|
const unBacktestRisk = riskSubject
|
|
55305
56111
|
.filter(({ backtest }) => backtest)
|
|
55306
|
-
.connect((data) =>
|
|
55307
|
-
|
|
55308
|
-
|
|
55309
|
-
|
|
55310
|
-
|
|
56112
|
+
.connect(async (data) => {
|
|
56113
|
+
if (risk) {
|
|
56114
|
+
await NotificationBacktest.handleRisk(data);
|
|
56115
|
+
}
|
|
56116
|
+
});
|
|
56117
|
+
const unBacktestError = errorEmitter.subscribe(async (error) => {
|
|
56118
|
+
if (common_error) {
|
|
56119
|
+
await NotificationBacktest.handleError(error);
|
|
56120
|
+
}
|
|
56121
|
+
});
|
|
56122
|
+
const unBacktestExit = exitEmitter.subscribe(async (error) => {
|
|
56123
|
+
if (critical_error) {
|
|
56124
|
+
await NotificationBacktest.handleCriticalError(error);
|
|
56125
|
+
}
|
|
56126
|
+
});
|
|
56127
|
+
const unBacktestValidation = validationSubject.subscribe(async (error) => {
|
|
56128
|
+
if (validation_error) {
|
|
56129
|
+
await NotificationBacktest.handleValidationError(error);
|
|
56130
|
+
}
|
|
56131
|
+
});
|
|
56132
|
+
const unBacktestSignalNotify = signalNotifySubject
|
|
56133
|
+
.filter(({ backtest }) => backtest)
|
|
56134
|
+
.connect(async (data) => {
|
|
56135
|
+
if (info) {
|
|
56136
|
+
await NotificationBacktest.handleSignalNotify(data);
|
|
56137
|
+
}
|
|
56138
|
+
});
|
|
56139
|
+
unBacktest = functoolsKit.compose(() => unBacktestSignal(), () => unBacktestPartialProfit(), () => unBacktestPartialLoss(), () => unBacktestBreakeven(), () => unBacktestStrategyCommit(), () => unBacktestSync(), () => unBacktestRisk(), () => unBacktestError(), () => unBacktestExit(), () => unBacktestValidation(), () => unBacktestSignalNotify());
|
|
55311
56140
|
}
|
|
55312
56141
|
{
|
|
55313
|
-
const unLiveSignal = signalLiveEmitter.subscribe((data) =>
|
|
56142
|
+
const unLiveSignal = signalLiveEmitter.subscribe(async (data) => {
|
|
56143
|
+
if (signal) {
|
|
56144
|
+
await NotificationLive.handleSignal(data);
|
|
56145
|
+
}
|
|
56146
|
+
});
|
|
55314
56147
|
const unLivePartialProfit = partialProfitSubject
|
|
55315
56148
|
.filter(({ backtest }) => !backtest)
|
|
55316
|
-
.connect((data) =>
|
|
56149
|
+
.connect(async (data) => {
|
|
56150
|
+
if (partial_profit) {
|
|
56151
|
+
await NotificationLive.handlePartialProfit(data);
|
|
56152
|
+
}
|
|
56153
|
+
});
|
|
55317
56154
|
const unLivePartialLoss = partialLossSubject
|
|
55318
56155
|
.filter(({ backtest }) => !backtest)
|
|
55319
|
-
.connect((data) =>
|
|
56156
|
+
.connect(async (data) => {
|
|
56157
|
+
if (partial_loss) {
|
|
56158
|
+
await NotificationLive.handlePartialLoss(data);
|
|
56159
|
+
}
|
|
56160
|
+
});
|
|
55320
56161
|
const unLiveBreakeven = breakevenSubject
|
|
55321
56162
|
.filter(({ backtest }) => !backtest)
|
|
55322
|
-
.connect((data) =>
|
|
56163
|
+
.connect(async (data) => {
|
|
56164
|
+
if (breakeven) {
|
|
56165
|
+
await NotificationLive.handleBreakeven(data);
|
|
56166
|
+
}
|
|
56167
|
+
});
|
|
55323
56168
|
const unLiveStrategyCommit = strategyCommitSubject
|
|
55324
56169
|
.filter(({ backtest }) => !backtest)
|
|
55325
|
-
.connect((data) =>
|
|
56170
|
+
.connect(async (data) => {
|
|
56171
|
+
if (strategy_commit) {
|
|
56172
|
+
await NotificationLive.handleStrategyCommit(data);
|
|
56173
|
+
}
|
|
56174
|
+
});
|
|
55326
56175
|
const unLiveSync = syncSubject
|
|
55327
56176
|
.filter(({ backtest }) => !backtest)
|
|
55328
|
-
.connect((data) =>
|
|
56177
|
+
.connect(async (data) => {
|
|
56178
|
+
if (signal_sync) {
|
|
56179
|
+
await NotificationLive.handleSync(data);
|
|
56180
|
+
}
|
|
56181
|
+
});
|
|
55329
56182
|
const unLiveRisk = riskSubject
|
|
55330
56183
|
.filter(({ backtest }) => !backtest)
|
|
55331
|
-
.connect((data) =>
|
|
55332
|
-
|
|
55333
|
-
|
|
55334
|
-
|
|
55335
|
-
|
|
56184
|
+
.connect(async (data) => {
|
|
56185
|
+
if (risk) {
|
|
56186
|
+
await NotificationLive.handleRisk(data);
|
|
56187
|
+
}
|
|
56188
|
+
});
|
|
56189
|
+
const unLiveError = errorEmitter.subscribe(async (error) => {
|
|
56190
|
+
if (common_error) {
|
|
56191
|
+
await NotificationLive.handleError(error);
|
|
56192
|
+
}
|
|
56193
|
+
});
|
|
56194
|
+
const unLiveExit = exitEmitter.subscribe(async (error) => {
|
|
56195
|
+
if (critical_error) {
|
|
56196
|
+
await NotificationLive.handleCriticalError(error);
|
|
56197
|
+
}
|
|
56198
|
+
});
|
|
56199
|
+
const unLiveValidation = validationSubject.subscribe(async (error) => {
|
|
56200
|
+
if (validation_error) {
|
|
56201
|
+
await NotificationLive.handleValidationError(error);
|
|
56202
|
+
}
|
|
56203
|
+
});
|
|
56204
|
+
const unLiveSignalNotify = signalNotifySubject
|
|
56205
|
+
.filter(({ backtest }) => !backtest)
|
|
56206
|
+
.connect(async (data) => {
|
|
56207
|
+
if (info) {
|
|
56208
|
+
await NotificationLive.handleSignalNotify(data);
|
|
56209
|
+
}
|
|
56210
|
+
});
|
|
56211
|
+
unLive = functoolsKit.compose(() => unLiveSignal(), () => unLivePartialProfit(), () => unLivePartialLoss(), () => unLiveBreakeven(), () => unLiveStrategyCommit(), () => unLiveSync(), () => unLiveRisk(), () => unLiveError(), () => unLiveExit(), () => unLiveValidation(), () => unLiveSignalNotify());
|
|
55336
56212
|
}
|
|
55337
56213
|
return () => {
|
|
55338
56214
|
unLive();
|
|
@@ -55570,11 +56446,17 @@ class CacheFnInstance {
|
|
|
55570
56446
|
return cached;
|
|
55571
56447
|
}
|
|
55572
56448
|
}
|
|
56449
|
+
const value = this.fn(...args);
|
|
55573
56450
|
const newCache = {
|
|
55574
56451
|
when: currentWhen,
|
|
55575
|
-
value
|
|
56452
|
+
value,
|
|
55576
56453
|
};
|
|
55577
56454
|
this._cacheMap.set(key, newCache);
|
|
56455
|
+
if (value && value instanceof Promise) {
|
|
56456
|
+
value.catch(() => {
|
|
56457
|
+
this._cacheMap.delete(key);
|
|
56458
|
+
});
|
|
56459
|
+
}
|
|
55578
56460
|
return newCache;
|
|
55579
56461
|
};
|
|
55580
56462
|
/**
|
|
@@ -56155,7 +57037,7 @@ class IntervalFnInstance {
|
|
|
56155
57037
|
* within the same interval or when `fn` itself returned `null`
|
|
56156
57038
|
* @throws Error if method context, execution context, or interval is missing
|
|
56157
57039
|
*/
|
|
56158
|
-
this.run =
|
|
57040
|
+
this.run = (...args) => {
|
|
56159
57041
|
backtest.loggerService.debug(INTERVAL_METHOD_NAME_RUN, { args });
|
|
56160
57042
|
const step = INTERVAL_MINUTES[this.interval];
|
|
56161
57043
|
{
|
|
@@ -56177,10 +57059,15 @@ class IntervalFnInstance {
|
|
|
56177
57059
|
if (this._stateMap.get(stateKey) === currentAligned) {
|
|
56178
57060
|
return null;
|
|
56179
57061
|
}
|
|
56180
|
-
const result =
|
|
57062
|
+
const result = this.fn.apply(null, args);
|
|
56181
57063
|
if (result !== null) {
|
|
56182
57064
|
this._stateMap.set(stateKey, currentAligned);
|
|
56183
57065
|
}
|
|
57066
|
+
if (result && result instanceof Promise) {
|
|
57067
|
+
result.catch(() => {
|
|
57068
|
+
this._stateMap.delete(stateKey);
|
|
57069
|
+
});
|
|
57070
|
+
}
|
|
56184
57071
|
return result;
|
|
56185
57072
|
};
|
|
56186
57073
|
/**
|
|
@@ -57788,6 +58675,7 @@ exports.commitPartialLoss = commitPartialLoss;
|
|
|
57788
58675
|
exports.commitPartialLossCost = commitPartialLossCost;
|
|
57789
58676
|
exports.commitPartialProfit = commitPartialProfit;
|
|
57790
58677
|
exports.commitPartialProfitCost = commitPartialProfitCost;
|
|
58678
|
+
exports.commitSignalNotify = commitSignalNotify;
|
|
57791
58679
|
exports.commitTrailingStop = commitTrailingStop;
|
|
57792
58680
|
exports.commitTrailingStopCost = commitTrailingStopCost;
|
|
57793
58681
|
exports.commitTrailingTake = commitTrailingTake;
|
|
@@ -57824,6 +58712,7 @@ exports.getMode = getMode;
|
|
|
57824
58712
|
exports.getNextCandles = getNextCandles;
|
|
57825
58713
|
exports.getOrderBook = getOrderBook;
|
|
57826
58714
|
exports.getPendingSignal = getPendingSignal;
|
|
58715
|
+
exports.getPositionActiveMinutes = getPositionActiveMinutes;
|
|
57827
58716
|
exports.getPositionCountdownMinutes = getPositionCountdownMinutes;
|
|
57828
58717
|
exports.getPositionDrawdownMinutes = getPositionDrawdownMinutes;
|
|
57829
58718
|
exports.getPositionEffectivePrice = getPositionEffectivePrice;
|
|
@@ -57852,6 +58741,7 @@ exports.getPositionPartialOverlap = getPositionPartialOverlap;
|
|
|
57852
58741
|
exports.getPositionPartials = getPositionPartials;
|
|
57853
58742
|
exports.getPositionPnlCost = getPositionPnlCost;
|
|
57854
58743
|
exports.getPositionPnlPercent = getPositionPnlPercent;
|
|
58744
|
+
exports.getPositionWaitingMinutes = getPositionWaitingMinutes;
|
|
57855
58745
|
exports.getRawCandles = getRawCandles;
|
|
57856
58746
|
exports.getRiskSchema = getRiskSchema;
|
|
57857
58747
|
exports.getScheduledSignal = getScheduledSignal;
|
|
@@ -57906,6 +58796,8 @@ exports.listenSignalBacktest = listenSignalBacktest;
|
|
|
57906
58796
|
exports.listenSignalBacktestOnce = listenSignalBacktestOnce;
|
|
57907
58797
|
exports.listenSignalLive = listenSignalLive;
|
|
57908
58798
|
exports.listenSignalLiveOnce = listenSignalLiveOnce;
|
|
58799
|
+
exports.listenSignalNotify = listenSignalNotify;
|
|
58800
|
+
exports.listenSignalNotifyOnce = listenSignalNotifyOnce;
|
|
57909
58801
|
exports.listenSignalOnce = listenSignalOnce;
|
|
57910
58802
|
exports.listenStrategyCommit = listenStrategyCommit;
|
|
57911
58803
|
exports.listenStrategyCommitOnce = listenStrategyCommitOnce;
|