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.mjs
CHANGED
|
@@ -127,6 +127,9 @@ const reportServices$1 = {
|
|
|
127
127
|
highestProfitReportService: Symbol('highestProfitReportService'),
|
|
128
128
|
maxDrawdownReportService: Symbol('maxDrawdownReportService'),
|
|
129
129
|
};
|
|
130
|
+
const helperServices$1 = {
|
|
131
|
+
notificationHelperService: Symbol('notificationHelperService'),
|
|
132
|
+
};
|
|
130
133
|
const validationServices$1 = {
|
|
131
134
|
exchangeValidationService: Symbol('exchangeValidationService'),
|
|
132
135
|
strategyValidationService: Symbol('strategyValidationService'),
|
|
@@ -152,6 +155,7 @@ const TYPES = {
|
|
|
152
155
|
...markdownServices$1,
|
|
153
156
|
...reportServices$1,
|
|
154
157
|
...validationServices$1,
|
|
158
|
+
...helperServices$1,
|
|
155
159
|
};
|
|
156
160
|
|
|
157
161
|
/**
|
|
@@ -744,6 +748,11 @@ const highestProfitSubject = new Subject();
|
|
|
744
748
|
* Allows users to track drawdown levels and implement custom risk management logic based on drawdown thresholds.
|
|
745
749
|
*/
|
|
746
750
|
const maxDrawdownSubject = new Subject();
|
|
751
|
+
/**
|
|
752
|
+
* Signal info emitter for user-defined informational notes on open positions.
|
|
753
|
+
* Emits when a strategy calls commitSignalInfo() to broadcast a custom annotation.
|
|
754
|
+
*/
|
|
755
|
+
const signalNotifySubject = new Subject();
|
|
747
756
|
|
|
748
757
|
var emitters = /*#__PURE__*/Object.freeze({
|
|
749
758
|
__proto__: null,
|
|
@@ -768,6 +777,7 @@ var emitters = /*#__PURE__*/Object.freeze({
|
|
|
768
777
|
signalBacktestEmitter: signalBacktestEmitter,
|
|
769
778
|
signalEmitter: signalEmitter,
|
|
770
779
|
signalLiveEmitter: signalLiveEmitter,
|
|
780
|
+
signalNotifySubject: signalNotifySubject,
|
|
771
781
|
strategyCommitSubject: strategyCommitSubject,
|
|
772
782
|
syncSubject: syncSubject,
|
|
773
783
|
validationSubject: validationSubject,
|
|
@@ -7953,6 +7963,40 @@ class ClientStrategy {
|
|
|
7953
7963
|
}
|
|
7954
7964
|
return Math.floor((timestamp - this._pendingSignal._peak.timestamp) / 60000);
|
|
7955
7965
|
}
|
|
7966
|
+
/**
|
|
7967
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
7968
|
+
*
|
|
7969
|
+
* Computed as elapsed minutes since `pendingAt` (the moment the signal was activated).
|
|
7970
|
+
* Returns null if no pending signal exists.
|
|
7971
|
+
*
|
|
7972
|
+
* @param symbol - Trading pair symbol
|
|
7973
|
+
* @param timestamp - Current Unix timestamp in milliseconds
|
|
7974
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
7975
|
+
*/
|
|
7976
|
+
async getPositionActiveMinutes(symbol, timestamp) {
|
|
7977
|
+
this.params.logger.debug("ClientStrategy getPositionActiveMinutes", { symbol });
|
|
7978
|
+
if (!this._pendingSignal) {
|
|
7979
|
+
return null;
|
|
7980
|
+
}
|
|
7981
|
+
return Math.floor((timestamp - this._pendingSignal.pendingAt) / 60000);
|
|
7982
|
+
}
|
|
7983
|
+
/**
|
|
7984
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
7985
|
+
*
|
|
7986
|
+
* Computed as elapsed minutes since `scheduledAt` (the moment the scheduled signal was created).
|
|
7987
|
+
* Returns null if no scheduled signal exists.
|
|
7988
|
+
*
|
|
7989
|
+
* @param symbol - Trading pair symbol
|
|
7990
|
+
* @param timestamp - Current Unix timestamp in milliseconds
|
|
7991
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
7992
|
+
*/
|
|
7993
|
+
async getPositionWaitingMinutes(symbol, timestamp) {
|
|
7994
|
+
this.params.logger.debug("ClientStrategy getPositionWaitingMinutes", { symbol });
|
|
7995
|
+
if (!this._scheduledSignal) {
|
|
7996
|
+
return null;
|
|
7997
|
+
}
|
|
7998
|
+
return Math.floor((timestamp - this._scheduledSignal.scheduledAt) / 60000);
|
|
7999
|
+
}
|
|
7956
8000
|
/**
|
|
7957
8001
|
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
7958
8002
|
*
|
|
@@ -10270,7 +10314,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
10270
10314
|
* @param backtest - Whether running in backtest mode
|
|
10271
10315
|
* @returns Unique string key for memoization
|
|
10272
10316
|
*/
|
|
10273
|
-
const CREATE_KEY_FN$
|
|
10317
|
+
const CREATE_KEY_FN$v = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10274
10318
|
const parts = [symbol, strategyName, exchangeName];
|
|
10275
10319
|
if (frameName)
|
|
10276
10320
|
parts.push(frameName);
|
|
@@ -10537,7 +10581,7 @@ class StrategyConnectionService {
|
|
|
10537
10581
|
* @param backtest - Whether running in backtest mode
|
|
10538
10582
|
* @returns Configured ClientStrategy instance
|
|
10539
10583
|
*/
|
|
10540
|
-
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
10584
|
+
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$v(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10541
10585
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
10542
10586
|
return new ClientStrategy({
|
|
10543
10587
|
symbol,
|
|
@@ -11054,6 +11098,46 @@ class StrategyConnectionService {
|
|
|
11054
11098
|
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
11055
11099
|
return await strategy.getPositionCountdownMinutes(symbol, timestamp);
|
|
11056
11100
|
};
|
|
11101
|
+
/**
|
|
11102
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
11103
|
+
*
|
|
11104
|
+
* Delegates to ClientStrategy.getPositionActiveMinutes().
|
|
11105
|
+
* Returns null if no pending signal exists.
|
|
11106
|
+
*
|
|
11107
|
+
* @param backtest - Whether running in backtest mode
|
|
11108
|
+
* @param symbol - Trading pair symbol
|
|
11109
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
11110
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
11111
|
+
*/
|
|
11112
|
+
this.getPositionActiveMinutes = async (backtest, symbol, context) => {
|
|
11113
|
+
this.loggerService.log("strategyConnectionService getPositionActiveMinutes", {
|
|
11114
|
+
symbol,
|
|
11115
|
+
context,
|
|
11116
|
+
});
|
|
11117
|
+
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
11118
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
11119
|
+
return await strategy.getPositionActiveMinutes(symbol, timestamp);
|
|
11120
|
+
};
|
|
11121
|
+
/**
|
|
11122
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
11123
|
+
*
|
|
11124
|
+
* Delegates to ClientStrategy.getPositionWaitingMinutes().
|
|
11125
|
+
* Returns null if no scheduled 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 waiting minutes (≥ 0) or null
|
|
11131
|
+
*/
|
|
11132
|
+
this.getPositionWaitingMinutes = async (backtest, symbol, context) => {
|
|
11133
|
+
this.loggerService.log("strategyConnectionService getPositionWaitingMinutes", {
|
|
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.getPositionWaitingMinutes(symbol, timestamp);
|
|
11140
|
+
};
|
|
11057
11141
|
/**
|
|
11058
11142
|
* Returns the best price reached in the profit direction during this position's life.
|
|
11059
11143
|
*
|
|
@@ -11458,7 +11542,7 @@ class StrategyConnectionService {
|
|
|
11458
11542
|
}
|
|
11459
11543
|
return;
|
|
11460
11544
|
}
|
|
11461
|
-
const key = CREATE_KEY_FN$
|
|
11545
|
+
const key = CREATE_KEY_FN$v(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
11462
11546
|
if (!this.getStrategy.has(key)) {
|
|
11463
11547
|
return;
|
|
11464
11548
|
}
|
|
@@ -12627,7 +12711,7 @@ class ClientRisk {
|
|
|
12627
12711
|
* @param backtest - Whether running in backtest mode
|
|
12628
12712
|
* @returns Unique string key for memoization
|
|
12629
12713
|
*/
|
|
12630
|
-
const CREATE_KEY_FN$
|
|
12714
|
+
const CREATE_KEY_FN$u = (riskName, exchangeName, frameName, backtest) => {
|
|
12631
12715
|
const parts = [riskName, exchangeName];
|
|
12632
12716
|
if (frameName)
|
|
12633
12717
|
parts.push(frameName);
|
|
@@ -12727,7 +12811,7 @@ class RiskConnectionService {
|
|
|
12727
12811
|
* @param backtest - True if backtest mode, false if live mode
|
|
12728
12812
|
* @returns Configured ClientRisk instance
|
|
12729
12813
|
*/
|
|
12730
|
-
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
12814
|
+
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$u(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
12731
12815
|
const schema = this.riskSchemaService.get(riskName);
|
|
12732
12816
|
return new ClientRisk({
|
|
12733
12817
|
...schema,
|
|
@@ -12796,7 +12880,7 @@ class RiskConnectionService {
|
|
|
12796
12880
|
payload,
|
|
12797
12881
|
});
|
|
12798
12882
|
if (payload) {
|
|
12799
|
-
const key = CREATE_KEY_FN$
|
|
12883
|
+
const key = CREATE_KEY_FN$u(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
12800
12884
|
this.getRisk.clear(key);
|
|
12801
12885
|
}
|
|
12802
12886
|
else {
|
|
@@ -13840,7 +13924,7 @@ class ClientAction {
|
|
|
13840
13924
|
* @param backtest - Whether running in backtest mode
|
|
13841
13925
|
* @returns Unique string key for memoization
|
|
13842
13926
|
*/
|
|
13843
|
-
const CREATE_KEY_FN$
|
|
13927
|
+
const CREATE_KEY_FN$t = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13844
13928
|
const parts = [actionName, strategyName, exchangeName];
|
|
13845
13929
|
if (frameName)
|
|
13846
13930
|
parts.push(frameName);
|
|
@@ -13892,7 +13976,7 @@ class ActionConnectionService {
|
|
|
13892
13976
|
* @param backtest - True if backtest mode, false if live mode
|
|
13893
13977
|
* @returns Configured ClientAction instance
|
|
13894
13978
|
*/
|
|
13895
|
-
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
13979
|
+
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$t(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13896
13980
|
const schema = this.actionSchemaService.get(actionName);
|
|
13897
13981
|
return new ClientAction({
|
|
13898
13982
|
...schema,
|
|
@@ -14103,7 +14187,7 @@ class ActionConnectionService {
|
|
|
14103
14187
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
14104
14188
|
return;
|
|
14105
14189
|
}
|
|
14106
|
-
const key = CREATE_KEY_FN$
|
|
14190
|
+
const key = CREATE_KEY_FN$t(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
14107
14191
|
if (!this.getAction.has(key)) {
|
|
14108
14192
|
return;
|
|
14109
14193
|
}
|
|
@@ -14114,14 +14198,14 @@ class ActionConnectionService {
|
|
|
14114
14198
|
}
|
|
14115
14199
|
}
|
|
14116
14200
|
|
|
14117
|
-
const METHOD_NAME_VALIDATE$
|
|
14201
|
+
const METHOD_NAME_VALIDATE$3 = "exchangeCoreService validate";
|
|
14118
14202
|
/**
|
|
14119
14203
|
* Creates a unique key for memoizing validate calls.
|
|
14120
14204
|
* Key format: "exchangeName"
|
|
14121
14205
|
* @param exchangeName - Exchange name
|
|
14122
14206
|
* @returns Unique string key for memoization
|
|
14123
14207
|
*/
|
|
14124
|
-
const CREATE_KEY_FN$
|
|
14208
|
+
const CREATE_KEY_FN$s = (exchangeName) => {
|
|
14125
14209
|
return exchangeName;
|
|
14126
14210
|
};
|
|
14127
14211
|
/**
|
|
@@ -14145,11 +14229,11 @@ class ExchangeCoreService {
|
|
|
14145
14229
|
* @param exchangeName - Name of the exchange to validate
|
|
14146
14230
|
* @returns Promise that resolves when validation is complete
|
|
14147
14231
|
*/
|
|
14148
|
-
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
14149
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14232
|
+
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$s(exchangeName), async (exchangeName) => {
|
|
14233
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$3, {
|
|
14150
14234
|
exchangeName,
|
|
14151
14235
|
});
|
|
14152
|
-
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$
|
|
14236
|
+
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$3);
|
|
14153
14237
|
});
|
|
14154
14238
|
/**
|
|
14155
14239
|
* Fetches historical candles with execution context.
|
|
@@ -14390,14 +14474,14 @@ class ExchangeCoreService {
|
|
|
14390
14474
|
}
|
|
14391
14475
|
}
|
|
14392
14476
|
|
|
14393
|
-
const METHOD_NAME_VALIDATE$
|
|
14477
|
+
const METHOD_NAME_VALIDATE$2 = "strategyCoreService validate";
|
|
14394
14478
|
/**
|
|
14395
14479
|
* Creates a unique key for memoizing validate calls.
|
|
14396
14480
|
* Key format: "strategyName:exchangeName:frameName"
|
|
14397
14481
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14398
14482
|
* @returns Unique string key for memoization
|
|
14399
14483
|
*/
|
|
14400
|
-
const CREATE_KEY_FN$
|
|
14484
|
+
const CREATE_KEY_FN$r = (context) => {
|
|
14401
14485
|
const parts = [context.strategyName, context.exchangeName];
|
|
14402
14486
|
if (context.frameName)
|
|
14403
14487
|
parts.push(context.frameName);
|
|
@@ -14429,16 +14513,16 @@ class StrategyCoreService {
|
|
|
14429
14513
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14430
14514
|
* @returns Promise that resolves when validation is complete
|
|
14431
14515
|
*/
|
|
14432
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
14433
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14516
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$r(context), async (context) => {
|
|
14517
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
14434
14518
|
context,
|
|
14435
14519
|
});
|
|
14436
14520
|
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
14437
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$
|
|
14438
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$
|
|
14439
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$
|
|
14440
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14441
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14521
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$2);
|
|
14522
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$2);
|
|
14523
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$2);
|
|
14524
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2);
|
|
14525
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2));
|
|
14442
14526
|
});
|
|
14443
14527
|
/**
|
|
14444
14528
|
* Retrieves the currently active pending signal for the symbol.
|
|
@@ -15374,6 +15458,38 @@ class StrategyCoreService {
|
|
|
15374
15458
|
await this.validate(context);
|
|
15375
15459
|
return await this.strategyConnectionService.getPositionCountdownMinutes(backtest, symbol, context);
|
|
15376
15460
|
};
|
|
15461
|
+
/**
|
|
15462
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
15463
|
+
*
|
|
15464
|
+
* @param backtest - Whether running in backtest mode
|
|
15465
|
+
* @param symbol - Trading pair symbol
|
|
15466
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15467
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
15468
|
+
*/
|
|
15469
|
+
this.getPositionActiveMinutes = async (backtest, symbol, context) => {
|
|
15470
|
+
this.loggerService.log("strategyCoreService getPositionActiveMinutes", {
|
|
15471
|
+
symbol,
|
|
15472
|
+
context,
|
|
15473
|
+
});
|
|
15474
|
+
await this.validate(context);
|
|
15475
|
+
return await this.strategyConnectionService.getPositionActiveMinutes(backtest, symbol, context);
|
|
15476
|
+
};
|
|
15477
|
+
/**
|
|
15478
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
15479
|
+
*
|
|
15480
|
+
* @param backtest - Whether running in backtest mode
|
|
15481
|
+
* @param symbol - Trading pair symbol
|
|
15482
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15483
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
15484
|
+
*/
|
|
15485
|
+
this.getPositionWaitingMinutes = async (backtest, symbol, context) => {
|
|
15486
|
+
this.loggerService.log("strategyCoreService getPositionWaitingMinutes", {
|
|
15487
|
+
symbol,
|
|
15488
|
+
context,
|
|
15489
|
+
});
|
|
15490
|
+
await this.validate(context);
|
|
15491
|
+
return await this.strategyConnectionService.getPositionWaitingMinutes(backtest, symbol, context);
|
|
15492
|
+
};
|
|
15377
15493
|
/**
|
|
15378
15494
|
* Returns the best price reached in the profit direction during this position's life.
|
|
15379
15495
|
*
|
|
@@ -15767,7 +15883,7 @@ class SizingGlobalService {
|
|
|
15767
15883
|
* @param context - Context with riskName, exchangeName, frameName
|
|
15768
15884
|
* @returns Unique string key for memoization
|
|
15769
15885
|
*/
|
|
15770
|
-
const CREATE_KEY_FN$
|
|
15886
|
+
const CREATE_KEY_FN$q = (context) => {
|
|
15771
15887
|
const parts = [context.riskName, context.exchangeName];
|
|
15772
15888
|
if (context.frameName)
|
|
15773
15889
|
parts.push(context.frameName);
|
|
@@ -15793,7 +15909,7 @@ class RiskGlobalService {
|
|
|
15793
15909
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
15794
15910
|
* @returns Promise that resolves when validation is complete
|
|
15795
15911
|
*/
|
|
15796
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
15912
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$q(context), async (context) => {
|
|
15797
15913
|
this.loggerService.log("riskGlobalService validate", {
|
|
15798
15914
|
context,
|
|
15799
15915
|
});
|
|
@@ -15864,14 +15980,14 @@ class RiskGlobalService {
|
|
|
15864
15980
|
}
|
|
15865
15981
|
}
|
|
15866
15982
|
|
|
15867
|
-
const METHOD_NAME_VALIDATE = "actionCoreService validate";
|
|
15983
|
+
const METHOD_NAME_VALIDATE$1 = "actionCoreService validate";
|
|
15868
15984
|
/**
|
|
15869
15985
|
* Creates a unique key for memoizing validate calls.
|
|
15870
15986
|
* Key format: "strategyName:exchangeName:frameName"
|
|
15871
15987
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15872
15988
|
* @returns Unique string key for memoization
|
|
15873
15989
|
*/
|
|
15874
|
-
const CREATE_KEY_FN$
|
|
15990
|
+
const CREATE_KEY_FN$p = (context) => {
|
|
15875
15991
|
const parts = [context.strategyName, context.exchangeName];
|
|
15876
15992
|
if (context.frameName)
|
|
15877
15993
|
parts.push(context.frameName);
|
|
@@ -15915,17 +16031,17 @@ class ActionCoreService {
|
|
|
15915
16031
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
15916
16032
|
* @returns Promise that resolves when all validations complete
|
|
15917
16033
|
*/
|
|
15918
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
15919
|
-
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
16034
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$p(context), async (context) => {
|
|
16035
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
15920
16036
|
context,
|
|
15921
16037
|
});
|
|
15922
16038
|
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
15923
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
15924
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
15925
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
15926
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
15927
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
15928
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
16039
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$1);
|
|
16040
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$1);
|
|
16041
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$1);
|
|
16042
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1);
|
|
16043
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1));
|
|
16044
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$1));
|
|
15929
16045
|
});
|
|
15930
16046
|
/**
|
|
15931
16047
|
* Initializes all ClientAction instances for the strategy.
|
|
@@ -20958,7 +21074,7 @@ const ReportWriter = new ReportWriterAdapter();
|
|
|
20958
21074
|
* @param backtest - Whether running in backtest mode
|
|
20959
21075
|
* @returns Unique string key for memoization
|
|
20960
21076
|
*/
|
|
20961
|
-
const CREATE_KEY_FN$
|
|
21077
|
+
const CREATE_KEY_FN$o = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
20962
21078
|
const parts = [symbol, strategyName, exchangeName];
|
|
20963
21079
|
if (frameName)
|
|
20964
21080
|
parts.push(frameName);
|
|
@@ -21204,7 +21320,7 @@ class BacktestMarkdownService {
|
|
|
21204
21320
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21205
21321
|
* Each combination gets its own isolated storage instance.
|
|
21206
21322
|
*/
|
|
21207
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21323
|
+
this.getStorage = 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));
|
|
21208
21324
|
/**
|
|
21209
21325
|
* Processes tick events and accumulates closed signals.
|
|
21210
21326
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -21361,7 +21477,7 @@ class BacktestMarkdownService {
|
|
|
21361
21477
|
payload,
|
|
21362
21478
|
});
|
|
21363
21479
|
if (payload) {
|
|
21364
|
-
const key = CREATE_KEY_FN$
|
|
21480
|
+
const key = CREATE_KEY_FN$o(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
21365
21481
|
this.getStorage.clear(key);
|
|
21366
21482
|
}
|
|
21367
21483
|
else {
|
|
@@ -21423,7 +21539,7 @@ class BacktestMarkdownService {
|
|
|
21423
21539
|
* @param backtest - Whether running in backtest mode
|
|
21424
21540
|
* @returns Unique string key for memoization
|
|
21425
21541
|
*/
|
|
21426
|
-
const CREATE_KEY_FN$
|
|
21542
|
+
const CREATE_KEY_FN$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21427
21543
|
const parts = [symbol, strategyName, exchangeName];
|
|
21428
21544
|
if (frameName)
|
|
21429
21545
|
parts.push(frameName);
|
|
@@ -21918,7 +22034,7 @@ class LiveMarkdownService {
|
|
|
21918
22034
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21919
22035
|
* Each combination gets its own isolated storage instance.
|
|
21920
22036
|
*/
|
|
21921
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22037
|
+
this.getStorage = 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));
|
|
21922
22038
|
/**
|
|
21923
22039
|
* Subscribes to live signal emitter to receive tick events.
|
|
21924
22040
|
* Protected against multiple subscriptions.
|
|
@@ -22136,7 +22252,7 @@ class LiveMarkdownService {
|
|
|
22136
22252
|
payload,
|
|
22137
22253
|
});
|
|
22138
22254
|
if (payload) {
|
|
22139
|
-
const key = CREATE_KEY_FN$
|
|
22255
|
+
const key = CREATE_KEY_FN$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22140
22256
|
this.getStorage.clear(key);
|
|
22141
22257
|
}
|
|
22142
22258
|
else {
|
|
@@ -22156,7 +22272,7 @@ class LiveMarkdownService {
|
|
|
22156
22272
|
* @param backtest - Whether running in backtest mode
|
|
22157
22273
|
* @returns Unique string key for memoization
|
|
22158
22274
|
*/
|
|
22159
|
-
const CREATE_KEY_FN$
|
|
22275
|
+
const CREATE_KEY_FN$m = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22160
22276
|
const parts = [symbol, strategyName, exchangeName];
|
|
22161
22277
|
if (frameName)
|
|
22162
22278
|
parts.push(frameName);
|
|
@@ -22445,7 +22561,7 @@ class ScheduleMarkdownService {
|
|
|
22445
22561
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22446
22562
|
* Each combination gets its own isolated storage instance.
|
|
22447
22563
|
*/
|
|
22448
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22564
|
+
this.getStorage = 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));
|
|
22449
22565
|
/**
|
|
22450
22566
|
* Subscribes to signal emitter to receive scheduled signal events.
|
|
22451
22567
|
* Protected against multiple subscriptions.
|
|
@@ -22648,7 +22764,7 @@ class ScheduleMarkdownService {
|
|
|
22648
22764
|
payload,
|
|
22649
22765
|
});
|
|
22650
22766
|
if (payload) {
|
|
22651
|
-
const key = CREATE_KEY_FN$
|
|
22767
|
+
const key = CREATE_KEY_FN$m(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22652
22768
|
this.getStorage.clear(key);
|
|
22653
22769
|
}
|
|
22654
22770
|
else {
|
|
@@ -22668,7 +22784,7 @@ class ScheduleMarkdownService {
|
|
|
22668
22784
|
* @param backtest - Whether running in backtest mode
|
|
22669
22785
|
* @returns Unique string key for memoization
|
|
22670
22786
|
*/
|
|
22671
|
-
const CREATE_KEY_FN$
|
|
22787
|
+
const CREATE_KEY_FN$l = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22672
22788
|
const parts = [symbol, strategyName, exchangeName];
|
|
22673
22789
|
if (frameName)
|
|
22674
22790
|
parts.push(frameName);
|
|
@@ -22913,7 +23029,7 @@ class PerformanceMarkdownService {
|
|
|
22913
23029
|
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22914
23030
|
* Each combination gets its own isolated storage instance.
|
|
22915
23031
|
*/
|
|
22916
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
23032
|
+
this.getStorage = 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));
|
|
22917
23033
|
/**
|
|
22918
23034
|
* Subscribes to performance emitter to receive performance events.
|
|
22919
23035
|
* Protected against multiple subscriptions.
|
|
@@ -23080,7 +23196,7 @@ class PerformanceMarkdownService {
|
|
|
23080
23196
|
payload,
|
|
23081
23197
|
});
|
|
23082
23198
|
if (payload) {
|
|
23083
|
-
const key = CREATE_KEY_FN$
|
|
23199
|
+
const key = CREATE_KEY_FN$l(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
23084
23200
|
this.getStorage.clear(key);
|
|
23085
23201
|
}
|
|
23086
23202
|
else {
|
|
@@ -23559,7 +23675,7 @@ class WalkerMarkdownService {
|
|
|
23559
23675
|
* @param backtest - Whether running in backtest mode
|
|
23560
23676
|
* @returns Unique string key for memoization
|
|
23561
23677
|
*/
|
|
23562
|
-
const CREATE_KEY_FN$
|
|
23678
|
+
const CREATE_KEY_FN$k = (exchangeName, frameName, backtest) => {
|
|
23563
23679
|
const parts = [exchangeName];
|
|
23564
23680
|
if (frameName)
|
|
23565
23681
|
parts.push(frameName);
|
|
@@ -24006,7 +24122,7 @@ class HeatMarkdownService {
|
|
|
24006
24122
|
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
24007
24123
|
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
24008
24124
|
*/
|
|
24009
|
-
this.getStorage = memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
24125
|
+
this.getStorage = memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$k(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
|
|
24010
24126
|
/**
|
|
24011
24127
|
* Subscribes to signal emitter to receive tick events.
|
|
24012
24128
|
* Protected against multiple subscriptions.
|
|
@@ -24224,7 +24340,7 @@ class HeatMarkdownService {
|
|
|
24224
24340
|
payload,
|
|
24225
24341
|
});
|
|
24226
24342
|
if (payload) {
|
|
24227
|
-
const key = CREATE_KEY_FN$
|
|
24343
|
+
const key = CREATE_KEY_FN$k(payload.exchangeName, payload.frameName, payload.backtest);
|
|
24228
24344
|
this.getStorage.clear(key);
|
|
24229
24345
|
}
|
|
24230
24346
|
else {
|
|
@@ -25255,7 +25371,7 @@ class ClientPartial {
|
|
|
25255
25371
|
* @param backtest - Whether running in backtest mode
|
|
25256
25372
|
* @returns Unique string key for memoization
|
|
25257
25373
|
*/
|
|
25258
|
-
const CREATE_KEY_FN$
|
|
25374
|
+
const CREATE_KEY_FN$j = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
25259
25375
|
/**
|
|
25260
25376
|
* Creates a callback function for emitting profit events to partialProfitSubject.
|
|
25261
25377
|
*
|
|
@@ -25377,7 +25493,7 @@ class PartialConnectionService {
|
|
|
25377
25493
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
25378
25494
|
* Value: ClientPartial instance with logger and event emitters
|
|
25379
25495
|
*/
|
|
25380
|
-
this.getPartial = memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
25496
|
+
this.getPartial = memoize(([signalId, backtest]) => CREATE_KEY_FN$j(signalId, backtest), (signalId, backtest) => {
|
|
25381
25497
|
return new ClientPartial({
|
|
25382
25498
|
signalId,
|
|
25383
25499
|
logger: this.loggerService,
|
|
@@ -25467,7 +25583,7 @@ class PartialConnectionService {
|
|
|
25467
25583
|
const partial = this.getPartial(data.id, backtest);
|
|
25468
25584
|
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
25469
25585
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
25470
|
-
const key = CREATE_KEY_FN$
|
|
25586
|
+
const key = CREATE_KEY_FN$j(data.id, backtest);
|
|
25471
25587
|
this.getPartial.clear(key);
|
|
25472
25588
|
};
|
|
25473
25589
|
}
|
|
@@ -25483,7 +25599,7 @@ class PartialConnectionService {
|
|
|
25483
25599
|
* @param backtest - Whether running in backtest mode
|
|
25484
25600
|
* @returns Unique string key for memoization
|
|
25485
25601
|
*/
|
|
25486
|
-
const CREATE_KEY_FN$
|
|
25602
|
+
const CREATE_KEY_FN$i = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
25487
25603
|
const parts = [symbol, strategyName, exchangeName];
|
|
25488
25604
|
if (frameName)
|
|
25489
25605
|
parts.push(frameName);
|
|
@@ -25706,7 +25822,7 @@ class PartialMarkdownService {
|
|
|
25706
25822
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
25707
25823
|
* Each combination gets its own isolated storage instance.
|
|
25708
25824
|
*/
|
|
25709
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
25825
|
+
this.getStorage = 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));
|
|
25710
25826
|
/**
|
|
25711
25827
|
* Subscribes to partial profit/loss signal emitters to receive events.
|
|
25712
25828
|
* Protected against multiple subscriptions.
|
|
@@ -25916,7 +26032,7 @@ class PartialMarkdownService {
|
|
|
25916
26032
|
payload,
|
|
25917
26033
|
});
|
|
25918
26034
|
if (payload) {
|
|
25919
|
-
const key = CREATE_KEY_FN$
|
|
26035
|
+
const key = CREATE_KEY_FN$i(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
25920
26036
|
this.getStorage.clear(key);
|
|
25921
26037
|
}
|
|
25922
26038
|
else {
|
|
@@ -25932,7 +26048,7 @@ class PartialMarkdownService {
|
|
|
25932
26048
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
25933
26049
|
* @returns Unique string key for memoization
|
|
25934
26050
|
*/
|
|
25935
|
-
const CREATE_KEY_FN$
|
|
26051
|
+
const CREATE_KEY_FN$h = (context) => {
|
|
25936
26052
|
const parts = [context.strategyName, context.exchangeName];
|
|
25937
26053
|
if (context.frameName)
|
|
25938
26054
|
parts.push(context.frameName);
|
|
@@ -26006,7 +26122,7 @@ class PartialGlobalService {
|
|
|
26006
26122
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
26007
26123
|
* @param methodName - Name of the calling method for error tracking
|
|
26008
26124
|
*/
|
|
26009
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
26125
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$h(context), (context, methodName) => {
|
|
26010
26126
|
this.loggerService.log("partialGlobalService validate", {
|
|
26011
26127
|
context,
|
|
26012
26128
|
methodName,
|
|
@@ -26461,7 +26577,7 @@ class ClientBreakeven {
|
|
|
26461
26577
|
* @param backtest - Whether running in backtest mode
|
|
26462
26578
|
* @returns Unique string key for memoization
|
|
26463
26579
|
*/
|
|
26464
|
-
const CREATE_KEY_FN$
|
|
26580
|
+
const CREATE_KEY_FN$g = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
26465
26581
|
/**
|
|
26466
26582
|
* Creates a callback function for emitting breakeven events to breakevenSubject.
|
|
26467
26583
|
*
|
|
@@ -26547,7 +26663,7 @@ class BreakevenConnectionService {
|
|
|
26547
26663
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
26548
26664
|
* Value: ClientBreakeven instance with logger and event emitter
|
|
26549
26665
|
*/
|
|
26550
|
-
this.getBreakeven = memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
26666
|
+
this.getBreakeven = memoize(([signalId, backtest]) => CREATE_KEY_FN$g(signalId, backtest), (signalId, backtest) => {
|
|
26551
26667
|
return new ClientBreakeven({
|
|
26552
26668
|
signalId,
|
|
26553
26669
|
logger: this.loggerService,
|
|
@@ -26608,7 +26724,7 @@ class BreakevenConnectionService {
|
|
|
26608
26724
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
26609
26725
|
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
26610
26726
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
26611
|
-
const key = CREATE_KEY_FN$
|
|
26727
|
+
const key = CREATE_KEY_FN$g(data.id, backtest);
|
|
26612
26728
|
this.getBreakeven.clear(key);
|
|
26613
26729
|
};
|
|
26614
26730
|
}
|
|
@@ -26624,7 +26740,7 @@ class BreakevenConnectionService {
|
|
|
26624
26740
|
* @param backtest - Whether running in backtest mode
|
|
26625
26741
|
* @returns Unique string key for memoization
|
|
26626
26742
|
*/
|
|
26627
|
-
const CREATE_KEY_FN$
|
|
26743
|
+
const CREATE_KEY_FN$f = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
26628
26744
|
const parts = [symbol, strategyName, exchangeName];
|
|
26629
26745
|
if (frameName)
|
|
26630
26746
|
parts.push(frameName);
|
|
@@ -26799,7 +26915,7 @@ class BreakevenMarkdownService {
|
|
|
26799
26915
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
26800
26916
|
* Each combination gets its own isolated storage instance.
|
|
26801
26917
|
*/
|
|
26802
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
26918
|
+
this.getStorage = 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));
|
|
26803
26919
|
/**
|
|
26804
26920
|
* Subscribes to breakeven signal emitter to receive events.
|
|
26805
26921
|
* Protected against multiple subscriptions.
|
|
@@ -26988,7 +27104,7 @@ class BreakevenMarkdownService {
|
|
|
26988
27104
|
payload,
|
|
26989
27105
|
});
|
|
26990
27106
|
if (payload) {
|
|
26991
|
-
const key = CREATE_KEY_FN$
|
|
27107
|
+
const key = CREATE_KEY_FN$f(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
26992
27108
|
this.getStorage.clear(key);
|
|
26993
27109
|
}
|
|
26994
27110
|
else {
|
|
@@ -27004,7 +27120,7 @@ class BreakevenMarkdownService {
|
|
|
27004
27120
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
27005
27121
|
* @returns Unique string key for memoization
|
|
27006
27122
|
*/
|
|
27007
|
-
const CREATE_KEY_FN$
|
|
27123
|
+
const CREATE_KEY_FN$e = (context) => {
|
|
27008
27124
|
const parts = [context.strategyName, context.exchangeName];
|
|
27009
27125
|
if (context.frameName)
|
|
27010
27126
|
parts.push(context.frameName);
|
|
@@ -27078,7 +27194,7 @@ class BreakevenGlobalService {
|
|
|
27078
27194
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
27079
27195
|
* @param methodName - Name of the calling method for error tracking
|
|
27080
27196
|
*/
|
|
27081
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
27197
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$e(context), (context, methodName) => {
|
|
27082
27198
|
this.loggerService.log("breakevenGlobalService validate", {
|
|
27083
27199
|
context,
|
|
27084
27200
|
methodName,
|
|
@@ -27299,7 +27415,7 @@ class ConfigValidationService {
|
|
|
27299
27415
|
* @param backtest - Whether running in backtest mode
|
|
27300
27416
|
* @returns Unique string key for memoization
|
|
27301
27417
|
*/
|
|
27302
|
-
const CREATE_KEY_FN$
|
|
27418
|
+
const CREATE_KEY_FN$d = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27303
27419
|
const parts = [symbol, strategyName, exchangeName];
|
|
27304
27420
|
if (frameName)
|
|
27305
27421
|
parts.push(frameName);
|
|
@@ -27466,7 +27582,7 @@ class RiskMarkdownService {
|
|
|
27466
27582
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27467
27583
|
* Each combination gets its own isolated storage instance.
|
|
27468
27584
|
*/
|
|
27469
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
27585
|
+
this.getStorage = 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));
|
|
27470
27586
|
/**
|
|
27471
27587
|
* Subscribes to risk rejection emitter to receive rejection events.
|
|
27472
27588
|
* Protected against multiple subscriptions.
|
|
@@ -27655,7 +27771,7 @@ class RiskMarkdownService {
|
|
|
27655
27771
|
payload,
|
|
27656
27772
|
});
|
|
27657
27773
|
if (payload) {
|
|
27658
|
-
const key = CREATE_KEY_FN$
|
|
27774
|
+
const key = CREATE_KEY_FN$d(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27659
27775
|
this.getStorage.clear(key);
|
|
27660
27776
|
}
|
|
27661
27777
|
else {
|
|
@@ -30037,7 +30153,7 @@ class HighestProfitReportService {
|
|
|
30037
30153
|
* @returns Colon-separated key string for memoization
|
|
30038
30154
|
* @internal
|
|
30039
30155
|
*/
|
|
30040
|
-
const CREATE_KEY_FN$
|
|
30156
|
+
const CREATE_KEY_FN$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30041
30157
|
const parts = [symbol, strategyName, exchangeName];
|
|
30042
30158
|
if (frameName)
|
|
30043
30159
|
parts.push(frameName);
|
|
@@ -30279,7 +30395,7 @@ class StrategyMarkdownService {
|
|
|
30279
30395
|
*
|
|
30280
30396
|
* @internal
|
|
30281
30397
|
*/
|
|
30282
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
30398
|
+
this.getStorage = 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));
|
|
30283
30399
|
/**
|
|
30284
30400
|
* Records a cancel-scheduled event when a scheduled signal is cancelled.
|
|
30285
30401
|
*
|
|
@@ -30853,7 +30969,7 @@ class StrategyMarkdownService {
|
|
|
30853
30969
|
this.clear = async (payload) => {
|
|
30854
30970
|
this.loggerService.log("strategyMarkdownService clear", { payload });
|
|
30855
30971
|
if (payload) {
|
|
30856
|
-
const key = CREATE_KEY_FN$
|
|
30972
|
+
const key = CREATE_KEY_FN$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
30857
30973
|
this.getStorage.clear(key);
|
|
30858
30974
|
}
|
|
30859
30975
|
else {
|
|
@@ -30961,7 +31077,7 @@ class StrategyMarkdownService {
|
|
|
30961
31077
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
30962
31078
|
* Key format: "symbol:strategyName:exchangeName[:frameName]:backtest|live"
|
|
30963
31079
|
*/
|
|
30964
|
-
const CREATE_KEY_FN$
|
|
31080
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30965
31081
|
const parts = [symbol, strategyName, exchangeName];
|
|
30966
31082
|
if (frameName)
|
|
30967
31083
|
parts.push(frameName);
|
|
@@ -31154,7 +31270,7 @@ let ReportStorage$2 = class ReportStorage {
|
|
|
31154
31270
|
class SyncMarkdownService {
|
|
31155
31271
|
constructor() {
|
|
31156
31272
|
this.loggerService = inject(TYPES.loggerService);
|
|
31157
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31273
|
+
this.getStorage = 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));
|
|
31158
31274
|
/**
|
|
31159
31275
|
* Subscribes to `syncSubject` to start receiving `SignalSyncContract` events.
|
|
31160
31276
|
* Protected against multiple subscriptions via `singleshot` — subsequent calls
|
|
@@ -31350,7 +31466,7 @@ class SyncMarkdownService {
|
|
|
31350
31466
|
this.clear = async (payload) => {
|
|
31351
31467
|
this.loggerService.log("syncMarkdownService clear", { payload });
|
|
31352
31468
|
if (payload) {
|
|
31353
|
-
const key = CREATE_KEY_FN$
|
|
31469
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31354
31470
|
this.getStorage.clear(key);
|
|
31355
31471
|
}
|
|
31356
31472
|
else {
|
|
@@ -31363,7 +31479,7 @@ class SyncMarkdownService {
|
|
|
31363
31479
|
/**
|
|
31364
31480
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31365
31481
|
*/
|
|
31366
|
-
const CREATE_KEY_FN$
|
|
31482
|
+
const CREATE_KEY_FN$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31367
31483
|
const parts = [symbol, strategyName, exchangeName];
|
|
31368
31484
|
if (frameName)
|
|
31369
31485
|
parts.push(frameName);
|
|
@@ -31539,7 +31655,7 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
31539
31655
|
class HighestProfitMarkdownService {
|
|
31540
31656
|
constructor() {
|
|
31541
31657
|
this.loggerService = inject(TYPES.loggerService);
|
|
31542
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31658
|
+
this.getStorage = 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));
|
|
31543
31659
|
/**
|
|
31544
31660
|
* Subscribes to `highestProfitSubject` to start receiving `HighestProfitContract`
|
|
31545
31661
|
* events. Protected against multiple subscriptions via `singleshot` — subsequent
|
|
@@ -31705,7 +31821,7 @@ class HighestProfitMarkdownService {
|
|
|
31705
31821
|
this.clear = async (payload) => {
|
|
31706
31822
|
this.loggerService.log("highestProfitMarkdownService clear", { payload });
|
|
31707
31823
|
if (payload) {
|
|
31708
|
-
const key = CREATE_KEY_FN$
|
|
31824
|
+
const key = CREATE_KEY_FN$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31709
31825
|
this.getStorage.clear(key);
|
|
31710
31826
|
}
|
|
31711
31827
|
else {
|
|
@@ -31727,7 +31843,7 @@ const LISTEN_TIMEOUT$1 = 120000;
|
|
|
31727
31843
|
* @param backtest - Whether running in backtest mode
|
|
31728
31844
|
* @returns Unique string key for memoization
|
|
31729
31845
|
*/
|
|
31730
|
-
const CREATE_KEY_FN$
|
|
31846
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31731
31847
|
const parts = [symbol, strategyName, exchangeName];
|
|
31732
31848
|
if (frameName)
|
|
31733
31849
|
parts.push(frameName);
|
|
@@ -31770,7 +31886,7 @@ class PriceMetaService {
|
|
|
31770
31886
|
* Each subject holds the latest currentPrice emitted by the strategy iterator for that key.
|
|
31771
31887
|
* Instances are cached until clear() is called.
|
|
31772
31888
|
*/
|
|
31773
|
-
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31889
|
+
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
31774
31890
|
/**
|
|
31775
31891
|
* Returns the current market price for the given symbol and context.
|
|
31776
31892
|
*
|
|
@@ -31799,10 +31915,10 @@ class PriceMetaService {
|
|
|
31799
31915
|
if (source.data) {
|
|
31800
31916
|
return source.data;
|
|
31801
31917
|
}
|
|
31802
|
-
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$
|
|
31918
|
+
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...`);
|
|
31803
31919
|
const currentPrice = await waitForNext(source, (data) => !!data, LISTEN_TIMEOUT$1);
|
|
31804
31920
|
if (typeof currentPrice === "symbol") {
|
|
31805
|
-
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$
|
|
31921
|
+
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31806
31922
|
}
|
|
31807
31923
|
return currentPrice;
|
|
31808
31924
|
};
|
|
@@ -31844,7 +31960,7 @@ class PriceMetaService {
|
|
|
31844
31960
|
this.getSource.clear();
|
|
31845
31961
|
return;
|
|
31846
31962
|
}
|
|
31847
|
-
const key = CREATE_KEY_FN$
|
|
31963
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31848
31964
|
this.getSource.clear(key);
|
|
31849
31965
|
};
|
|
31850
31966
|
}
|
|
@@ -31862,7 +31978,7 @@ const LISTEN_TIMEOUT = 120000;
|
|
|
31862
31978
|
* @param backtest - Whether running in backtest mode
|
|
31863
31979
|
* @returns Unique string key for memoization
|
|
31864
31980
|
*/
|
|
31865
|
-
const CREATE_KEY_FN$
|
|
31981
|
+
const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31866
31982
|
const parts = [symbol, strategyName, exchangeName];
|
|
31867
31983
|
if (frameName)
|
|
31868
31984
|
parts.push(frameName);
|
|
@@ -31905,7 +32021,7 @@ class TimeMetaService {
|
|
|
31905
32021
|
* Each subject holds the latest createdAt timestamp emitted by the strategy iterator for that key.
|
|
31906
32022
|
* Instances are cached until clear() is called.
|
|
31907
32023
|
*/
|
|
31908
|
-
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32024
|
+
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
31909
32025
|
/**
|
|
31910
32026
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
31911
32027
|
*
|
|
@@ -31933,10 +32049,10 @@ class TimeMetaService {
|
|
|
31933
32049
|
if (source.data) {
|
|
31934
32050
|
return source.data;
|
|
31935
32051
|
}
|
|
31936
|
-
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$
|
|
32052
|
+
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...`);
|
|
31937
32053
|
const timestamp = await waitForNext(source, (data) => !!data, LISTEN_TIMEOUT);
|
|
31938
32054
|
if (typeof timestamp === "symbol") {
|
|
31939
|
-
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$
|
|
32055
|
+
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31940
32056
|
}
|
|
31941
32057
|
return timestamp;
|
|
31942
32058
|
};
|
|
@@ -31978,7 +32094,7 @@ class TimeMetaService {
|
|
|
31978
32094
|
this.getSource.clear();
|
|
31979
32095
|
return;
|
|
31980
32096
|
}
|
|
31981
|
-
const key = CREATE_KEY_FN$
|
|
32097
|
+
const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31982
32098
|
this.getSource.clear(key);
|
|
31983
32099
|
};
|
|
31984
32100
|
}
|
|
@@ -32074,7 +32190,7 @@ class MaxDrawdownReportService {
|
|
|
32074
32190
|
/**
|
|
32075
32191
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
32076
32192
|
*/
|
|
32077
|
-
const CREATE_KEY_FN$
|
|
32193
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
32078
32194
|
const parts = [symbol, strategyName, exchangeName];
|
|
32079
32195
|
if (frameName)
|
|
32080
32196
|
parts.push(frameName);
|
|
@@ -32198,7 +32314,7 @@ class ReportStorage {
|
|
|
32198
32314
|
class MaxDrawdownMarkdownService {
|
|
32199
32315
|
constructor() {
|
|
32200
32316
|
this.loggerService = inject(TYPES.loggerService);
|
|
32201
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32317
|
+
this.getStorage = 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));
|
|
32202
32318
|
/**
|
|
32203
32319
|
* Subscribes to `maxDrawdownSubject` to start receiving `MaxDrawdownContract`
|
|
32204
32320
|
* events. Protected against multiple subscriptions via `singleshot`.
|
|
@@ -32277,7 +32393,7 @@ class MaxDrawdownMarkdownService {
|
|
|
32277
32393
|
this.clear = async (payload) => {
|
|
32278
32394
|
this.loggerService.log("maxDrawdownMarkdownService clear", { payload });
|
|
32279
32395
|
if (payload) {
|
|
32280
|
-
const key = CREATE_KEY_FN$
|
|
32396
|
+
const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32281
32397
|
this.getStorage.clear(key);
|
|
32282
32398
|
}
|
|
32283
32399
|
else {
|
|
@@ -32287,6 +32403,125 @@ class MaxDrawdownMarkdownService {
|
|
|
32287
32403
|
}
|
|
32288
32404
|
}
|
|
32289
32405
|
|
|
32406
|
+
const METHOD_NAME_COMMIT_SIGNAL_NOTIFY = "notificationHelperService.commitSignalNotify";
|
|
32407
|
+
const METHOD_NAME_VALIDATE = "notificationHelperService.validate";
|
|
32408
|
+
/**
|
|
32409
|
+
* Creates a unique key for memoizing validate calls.
|
|
32410
|
+
* Key format: "strategyName:exchangeName:frameName"
|
|
32411
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
32412
|
+
* @returns Unique string key for memoization
|
|
32413
|
+
*/
|
|
32414
|
+
const CREATE_KEY_FN$6 = (context) => {
|
|
32415
|
+
const parts = [context.strategyName, context.exchangeName];
|
|
32416
|
+
if (context.frameName)
|
|
32417
|
+
parts.push(context.frameName);
|
|
32418
|
+
return parts.join(":");
|
|
32419
|
+
};
|
|
32420
|
+
/**
|
|
32421
|
+
* Helper service for emitting signal info notifications.
|
|
32422
|
+
*
|
|
32423
|
+
* Handles validation (memoized per context) and emission of `signal.info` events
|
|
32424
|
+
* via `signalNotifySubject`. Used internally by the framework action pipeline —
|
|
32425
|
+
* end users interact with this via `commitSignalNotify()` in `onActivePing` callbacks.
|
|
32426
|
+
*/
|
|
32427
|
+
class NotificationHelperService {
|
|
32428
|
+
constructor() {
|
|
32429
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
32430
|
+
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
32431
|
+
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
32432
|
+
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
32433
|
+
this.exchangeValidationService = inject(TYPES.exchangeValidationService);
|
|
32434
|
+
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
32435
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
32436
|
+
this.strategyCoreService = inject(TYPES.strategyCoreService);
|
|
32437
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
32438
|
+
/**
|
|
32439
|
+
* Validates strategy, exchange, frame, risk, and action schemas for the given context.
|
|
32440
|
+
*
|
|
32441
|
+
* Memoized per unique `"strategyName:exchangeName[:frameName]"` key — subsequent calls
|
|
32442
|
+
* with the same context are no-ops, so validation runs at most once per context.
|
|
32443
|
+
*
|
|
32444
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32445
|
+
* @throws {Error} If any registered schema fails validation
|
|
32446
|
+
*/
|
|
32447
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$6(context), async (context) => {
|
|
32448
|
+
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
32449
|
+
context,
|
|
32450
|
+
});
|
|
32451
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
32452
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
32453
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
32454
|
+
context.frameName &&
|
|
32455
|
+
this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
32456
|
+
riskName &&
|
|
32457
|
+
this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
32458
|
+
riskList &&
|
|
32459
|
+
riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
32460
|
+
actions &&
|
|
32461
|
+
actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
32462
|
+
});
|
|
32463
|
+
/**
|
|
32464
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
32465
|
+
*
|
|
32466
|
+
* Validates all schemas (via memoized `validate`), resolves the pending signal
|
|
32467
|
+
* for the given symbol, then emits a `SignalInfoContract` via `signalNotifySubject`,
|
|
32468
|
+
* which is routed to all registered `listenSignalNotify` callbacks and persisted
|
|
32469
|
+
* by `NotificationAdapter`.
|
|
32470
|
+
*
|
|
32471
|
+
* @param payload - Optional notification fields (notificationId, notificationNote)
|
|
32472
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
32473
|
+
* @param currentPrice - Market price at the time of the call
|
|
32474
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32475
|
+
* @param backtest - true when called during a backtest run
|
|
32476
|
+
*
|
|
32477
|
+
* @throws {Error} If no active pending signal is found for the given symbol
|
|
32478
|
+
*
|
|
32479
|
+
* @example
|
|
32480
|
+
* ```typescript
|
|
32481
|
+
* // Inside onActivePing callback:
|
|
32482
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
32483
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
32484
|
+
* notificationId: "msg-123",
|
|
32485
|
+
* });
|
|
32486
|
+
* ```
|
|
32487
|
+
*/
|
|
32488
|
+
this.commitSignalNotify = async (payload, symbol, currentPrice, context, backtest) => {
|
|
32489
|
+
this.loggerService.info(METHOD_NAME_COMMIT_SIGNAL_NOTIFY, {
|
|
32490
|
+
symbol,
|
|
32491
|
+
context,
|
|
32492
|
+
backtest,
|
|
32493
|
+
currentPrice,
|
|
32494
|
+
});
|
|
32495
|
+
this.validate(context);
|
|
32496
|
+
const pendingSignal = await this.strategyCoreService.getPendingSignal(backtest, symbol, currentPrice, {
|
|
32497
|
+
strategyName: context.strategyName,
|
|
32498
|
+
exchangeName: context.exchangeName,
|
|
32499
|
+
frameName: context.frameName,
|
|
32500
|
+
});
|
|
32501
|
+
if (!pendingSignal) {
|
|
32502
|
+
throw new Error(`SignalUtils notify No pending signal found symbol=${symbol} `);
|
|
32503
|
+
}
|
|
32504
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, {
|
|
32505
|
+
strategyName: context.strategyName,
|
|
32506
|
+
exchangeName: context.exchangeName,
|
|
32507
|
+
frameName: context.frameName,
|
|
32508
|
+
}, backtest);
|
|
32509
|
+
await signalNotifySubject.next({
|
|
32510
|
+
backtest,
|
|
32511
|
+
symbol,
|
|
32512
|
+
currentPrice,
|
|
32513
|
+
data: pendingSignal,
|
|
32514
|
+
exchangeName: context.exchangeName,
|
|
32515
|
+
strategyName: context.strategyName,
|
|
32516
|
+
frameName: context.frameName,
|
|
32517
|
+
note: payload.notificationNote || pendingSignal.note,
|
|
32518
|
+
notificationId: payload.notificationId,
|
|
32519
|
+
timestamp,
|
|
32520
|
+
});
|
|
32521
|
+
};
|
|
32522
|
+
}
|
|
32523
|
+
}
|
|
32524
|
+
|
|
32290
32525
|
{
|
|
32291
32526
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
32292
32527
|
}
|
|
@@ -32375,6 +32610,9 @@ class MaxDrawdownMarkdownService {
|
|
|
32375
32610
|
provide(TYPES.highestProfitReportService, () => new HighestProfitReportService());
|
|
32376
32611
|
provide(TYPES.maxDrawdownReportService, () => new MaxDrawdownReportService());
|
|
32377
32612
|
}
|
|
32613
|
+
{
|
|
32614
|
+
provide(TYPES.notificationHelperService, () => new NotificationHelperService());
|
|
32615
|
+
}
|
|
32378
32616
|
{
|
|
32379
32617
|
provide(TYPES.exchangeValidationService, () => new ExchangeValidationService());
|
|
32380
32618
|
provide(TYPES.strategyValidationService, () => new StrategyValidationService());
|
|
@@ -32475,6 +32713,9 @@ const reportServices = {
|
|
|
32475
32713
|
highestProfitReportService: inject(TYPES.highestProfitReportService),
|
|
32476
32714
|
maxDrawdownReportService: inject(TYPES.maxDrawdownReportService),
|
|
32477
32715
|
};
|
|
32716
|
+
const helperServices = {
|
|
32717
|
+
notificationHelperService: inject(TYPES.notificationHelperService),
|
|
32718
|
+
};
|
|
32478
32719
|
const validationServices = {
|
|
32479
32720
|
exchangeValidationService: inject(TYPES.exchangeValidationService),
|
|
32480
32721
|
strategyValidationService: inject(TYPES.strategyValidationService),
|
|
@@ -32500,6 +32741,7 @@ const backtest = {
|
|
|
32500
32741
|
...markdownServices,
|
|
32501
32742
|
...reportServices,
|
|
32502
32743
|
...validationServices,
|
|
32744
|
+
...helperServices,
|
|
32503
32745
|
};
|
|
32504
32746
|
init();
|
|
32505
32747
|
|
|
@@ -35394,6 +35636,8 @@ const GET_POSITION_PARTIALS_METHOD_NAME = "strategy.getPositionPartials";
|
|
|
35394
35636
|
const GET_POSITION_ENTRIES_METHOD_NAME = "strategy.getPositionEntries";
|
|
35395
35637
|
const GET_POSITION_ESTIMATE_MINUTES_METHOD_NAME = "strategy.getPositionEstimateMinutes";
|
|
35396
35638
|
const GET_POSITION_COUNTDOWN_MINUTES_METHOD_NAME = "strategy.getPositionCountdownMinutes";
|
|
35639
|
+
const GET_POSITION_ACTIVE_MINUTES_METHOD_NAME = "strategy.getPositionActiveMinutes";
|
|
35640
|
+
const GET_POSITION_WAITING_MINUTES_METHOD_NAME = "strategy.getPositionWaitingMinutes";
|
|
35397
35641
|
const GET_POSITION_HIGHEST_PROFIT_PRICE_METHOD_NAME = "strategy.getPositionHighestProfitPrice";
|
|
35398
35642
|
const GET_POSITION_HIGHEST_PROFIT_TIMESTAMP_METHOD_NAME = "strategy.getPositionHighestProfitTimestamp";
|
|
35399
35643
|
const GET_POSITION_HIGHEST_PNL_PERCENTAGE_METHOD_NAME = "strategy.getPositionHighestPnlPercentage";
|
|
@@ -35416,6 +35660,7 @@ const GET_POSITION_ENTRY_OVERLAP_METHOD_NAME = "strategy.getPositionEntryOverlap
|
|
|
35416
35660
|
const GET_POSITION_PARTIAL_OVERLAP_METHOD_NAME = "strategy.getPositionPartialOverlap";
|
|
35417
35661
|
const HAS_NO_PENDING_SIGNAL_METHOD_NAME = "strategy.hasNoPendingSignal";
|
|
35418
35662
|
const HAS_NO_SCHEDULED_SIGNAL_METHOD_NAME = "strategy.hasNoScheduledSignal";
|
|
35663
|
+
const COMMIT_SIGNAL_NOTIFY_METHOD_NAME = "strategy.commitSignalNotify";
|
|
35419
35664
|
/**
|
|
35420
35665
|
* Cancels the scheduled signal without stopping the strategy.
|
|
35421
35666
|
*
|
|
@@ -36693,6 +36938,62 @@ async function getPositionCountdownMinutes(symbol) {
|
|
|
36693
36938
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36694
36939
|
return await backtest.strategyCoreService.getPositionCountdownMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36695
36940
|
}
|
|
36941
|
+
/**
|
|
36942
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
36943
|
+
*
|
|
36944
|
+
* Returns null if no pending signal exists.
|
|
36945
|
+
*
|
|
36946
|
+
* @param symbol - Trading pair symbol
|
|
36947
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
36948
|
+
*
|
|
36949
|
+
* @example
|
|
36950
|
+
* ```typescript
|
|
36951
|
+
* import { getPositionActiveMinutes } from "backtest-kit";
|
|
36952
|
+
*
|
|
36953
|
+
* const minutes = await getPositionActiveMinutes("BTCUSDT");
|
|
36954
|
+
* // e.g. 120 (position has been open for 2 hours)
|
|
36955
|
+
* ```
|
|
36956
|
+
*/
|
|
36957
|
+
async function getPositionActiveMinutes(symbol) {
|
|
36958
|
+
backtest.loggerService.info(GET_POSITION_ACTIVE_MINUTES_METHOD_NAME, { symbol });
|
|
36959
|
+
if (!ExecutionContextService.hasContext()) {
|
|
36960
|
+
throw new Error("getPositionActiveMinutes requires an execution context");
|
|
36961
|
+
}
|
|
36962
|
+
if (!MethodContextService.hasContext()) {
|
|
36963
|
+
throw new Error("getPositionActiveMinutes requires a method context");
|
|
36964
|
+
}
|
|
36965
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
36966
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36967
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36968
|
+
}
|
|
36969
|
+
/**
|
|
36970
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
36971
|
+
*
|
|
36972
|
+
* Returns null if no scheduled signal exists.
|
|
36973
|
+
*
|
|
36974
|
+
* @param symbol - Trading pair symbol
|
|
36975
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
36976
|
+
*
|
|
36977
|
+
* @example
|
|
36978
|
+
* ```typescript
|
|
36979
|
+
* import { getPositionWaitingMinutes } from "backtest-kit";
|
|
36980
|
+
*
|
|
36981
|
+
* const minutes = await getPositionWaitingMinutes("BTCUSDT");
|
|
36982
|
+
* // e.g. 15 (scheduled signal has been waiting 15 minutes for activation)
|
|
36983
|
+
* ```
|
|
36984
|
+
*/
|
|
36985
|
+
async function getPositionWaitingMinutes(symbol) {
|
|
36986
|
+
backtest.loggerService.info(GET_POSITION_WAITING_MINUTES_METHOD_NAME, { symbol });
|
|
36987
|
+
if (!ExecutionContextService.hasContext()) {
|
|
36988
|
+
throw new Error("getPositionWaitingMinutes requires an execution context");
|
|
36989
|
+
}
|
|
36990
|
+
if (!MethodContextService.hasContext()) {
|
|
36991
|
+
throw new Error("getPositionWaitingMinutes requires a method context");
|
|
36992
|
+
}
|
|
36993
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
36994
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
36995
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(isBacktest, symbol, { exchangeName, frameName, strategyName });
|
|
36996
|
+
}
|
|
36696
36997
|
/**
|
|
36697
36998
|
* Returns the best price reached in the profit direction during this position's life.
|
|
36698
36999
|
*
|
|
@@ -37380,6 +37681,50 @@ async function hasNoScheduledSignal(symbol) {
|
|
|
37380
37681
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37381
37682
|
return await not(backtest.strategyCoreService.hasScheduledSignal(isBacktest, symbol, { exchangeName, frameName, strategyName }));
|
|
37382
37683
|
}
|
|
37684
|
+
/**
|
|
37685
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
37686
|
+
*
|
|
37687
|
+
* Broadcasts a user-defined informational note without affecting position state.
|
|
37688
|
+
* Useful for annotating strategy decisions, triggering external alerts, or logging
|
|
37689
|
+
* mid-position events (e.g. RSI crossing a threshold, volume spike detected).
|
|
37690
|
+
*
|
|
37691
|
+
* Automatically reads backtest/live mode from execution context.
|
|
37692
|
+
* Automatically reads strategyName, exchangeName, frameName from method context.
|
|
37693
|
+
* Automatically fetches current price via getAveragePrice.
|
|
37694
|
+
*
|
|
37695
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
37696
|
+
* @param payload - Optional notification fields
|
|
37697
|
+
* @param payload.notificationNote - Human-readable note. Falls back to signal.note if omitted.
|
|
37698
|
+
* @param payload.notificationId - Optional correlation ID for external systems (e.g. Telegram message ID).
|
|
37699
|
+
*
|
|
37700
|
+
* @throws {Error} If called outside an execution context
|
|
37701
|
+
* @throws {Error} If called outside a method context
|
|
37702
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
37703
|
+
*
|
|
37704
|
+
* @example
|
|
37705
|
+
* ```typescript
|
|
37706
|
+
* import { commitSignalNotify } from "backtest-kit";
|
|
37707
|
+
*
|
|
37708
|
+
* // Inside onActivePing callback:
|
|
37709
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
37710
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
37711
|
+
* notificationId: "msg-123",
|
|
37712
|
+
* });
|
|
37713
|
+
* ```
|
|
37714
|
+
*/
|
|
37715
|
+
async function commitSignalNotify(symbol, payload = {}) {
|
|
37716
|
+
backtest.loggerService.info(COMMIT_SIGNAL_NOTIFY_METHOD_NAME, { symbol, payload });
|
|
37717
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37718
|
+
throw new Error("commitSignalNotify requires an execution context");
|
|
37719
|
+
}
|
|
37720
|
+
if (!MethodContextService.hasContext()) {
|
|
37721
|
+
throw new Error("commitSignalNotify requires a method context");
|
|
37722
|
+
}
|
|
37723
|
+
const currentPrice = await getAveragePrice(symbol);
|
|
37724
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37725
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37726
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, { strategyName, exchangeName, frameName }, isBacktest);
|
|
37727
|
+
}
|
|
37383
37728
|
|
|
37384
37729
|
const STOP_STRATEGY_METHOD_NAME = "control.stopStrategy";
|
|
37385
37730
|
/**
|
|
@@ -37463,6 +37808,8 @@ const LISTEN_HIGHEST_PROFIT_METHOD_NAME = "event.listenHighestProfit";
|
|
|
37463
37808
|
const LISTEN_HIGHEST_PROFIT_ONCE_METHOD_NAME = "event.listenHighestProfitOnce";
|
|
37464
37809
|
const LISTEN_MAX_DRAWDOWN_METHOD_NAME = "event.listenMaxDrawdown";
|
|
37465
37810
|
const LISTEN_MAX_DRAWDOWN_ONCE_METHOD_NAME = "event.listenMaxDrawdownOnce";
|
|
37811
|
+
const LISTEN_SIGNAL_NOTIFY_METHOD_NAME = "event.listenSignalNotify";
|
|
37812
|
+
const LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME = "event.listenSignalNotifyOnce";
|
|
37466
37813
|
/**
|
|
37467
37814
|
* Subscribes to all signal events with queued async processing.
|
|
37468
37815
|
*
|
|
@@ -38854,6 +39201,46 @@ function listenMaxDrawdownOnce(filterFn, fn) {
|
|
|
38854
39201
|
};
|
|
38855
39202
|
return disposeFn = listenMaxDrawdown(wrappedFn);
|
|
38856
39203
|
}
|
|
39204
|
+
/**
|
|
39205
|
+
* Subscribes to signal info events with queued async processing.
|
|
39206
|
+
* Emits when a strategy calls commitSignalInfo() to broadcast a user-defined note for an open position.
|
|
39207
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
39208
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
39209
|
+
* @param fn - Callback function to handle signal info events
|
|
39210
|
+
* @return Unsubscribe function to stop listening to events
|
|
39211
|
+
*/
|
|
39212
|
+
function listenSignalNotify(fn) {
|
|
39213
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_METHOD_NAME);
|
|
39214
|
+
const wrappedFn = async (event) => {
|
|
39215
|
+
if (await backtest.strategyCoreService.hasPendingSignal(event.backtest, event.symbol, {
|
|
39216
|
+
strategyName: event.strategyName,
|
|
39217
|
+
exchangeName: event.exchangeName,
|
|
39218
|
+
frameName: event.frameName,
|
|
39219
|
+
})) {
|
|
39220
|
+
await fn(event);
|
|
39221
|
+
}
|
|
39222
|
+
};
|
|
39223
|
+
return signalNotifySubject.subscribe(queued(wrappedFn));
|
|
39224
|
+
}
|
|
39225
|
+
/**
|
|
39226
|
+
* Subscribes to filtered signal info events with one-time execution.
|
|
39227
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
39228
|
+
* and automatically unsubscribes.
|
|
39229
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
39230
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
39231
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
39232
|
+
*/
|
|
39233
|
+
function listenSignalNotifyOnce(filterFn, fn) {
|
|
39234
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME);
|
|
39235
|
+
let disposeFn;
|
|
39236
|
+
const wrappedFn = async (event) => {
|
|
39237
|
+
if (filterFn(event)) {
|
|
39238
|
+
await fn(event);
|
|
39239
|
+
disposeFn && disposeFn();
|
|
39240
|
+
}
|
|
39241
|
+
};
|
|
39242
|
+
return disposeFn = listenSignalNotify(wrappedFn);
|
|
39243
|
+
}
|
|
38857
39244
|
|
|
38858
39245
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
38859
39246
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
@@ -38877,6 +39264,8 @@ const BACKTEST_METHOD_NAME_GET_POSITION_PARTIALS = "BacktestUtils.getPositionPar
|
|
|
38877
39264
|
const BACKTEST_METHOD_NAME_GET_POSITION_ENTRIES = "BacktestUtils.getPositionEntries";
|
|
38878
39265
|
const BACKTEST_METHOD_NAME_GET_POSITION_ESTIMATE_MINUTES = "BacktestUtils.getPositionEstimateMinutes";
|
|
38879
39266
|
const BACKTEST_METHOD_NAME_GET_POSITION_COUNTDOWN_MINUTES = "BacktestUtils.getPositionCountdownMinutes";
|
|
39267
|
+
const BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "BacktestUtils.getPositionActiveMinutes";
|
|
39268
|
+
const BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "BacktestUtils.getPositionWaitingMinutes";
|
|
38880
39269
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE = "BacktestUtils.getPositionHighestProfitPrice";
|
|
38881
39270
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "BacktestUtils.getPositionHighestProfitTimestamp";
|
|
38882
39271
|
const BACKTEST_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "BacktestUtils.getPositionHighestPnlPercentage";
|
|
@@ -38910,6 +39299,7 @@ const BACKTEST_METHOD_NAME_TRAILING_STOP_COST = "BacktestUtils.commitTrailingSto
|
|
|
38910
39299
|
const BACKTEST_METHOD_NAME_TRAILING_PROFIT_COST = "BacktestUtils.commitTrailingTakeCost";
|
|
38911
39300
|
const BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED = "Backtest.commitActivateScheduled";
|
|
38912
39301
|
const BACKTEST_METHOD_NAME_AVERAGE_BUY = "Backtest.commitAverageBuy";
|
|
39302
|
+
const BACKTEST_METHOD_NAME_SIGNAL_NOTIFY = "Backtest.commitSignalNotify";
|
|
38913
39303
|
const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
|
|
38914
39304
|
const BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "BacktestUtils.hasNoPendingSignal";
|
|
38915
39305
|
const BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "BacktestUtils.hasNoScheduledSignal";
|
|
@@ -39831,6 +40221,60 @@ class BacktestUtils {
|
|
|
39831
40221
|
}
|
|
39832
40222
|
return await backtest.strategyCoreService.getPositionCountdownMinutes(true, symbol, context);
|
|
39833
40223
|
};
|
|
40224
|
+
/**
|
|
40225
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
40226
|
+
*
|
|
40227
|
+
* Returns null if no pending signal exists.
|
|
40228
|
+
*
|
|
40229
|
+
* @param symbol - Trading pair symbol
|
|
40230
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40231
|
+
* @returns Active minutes (≥ 0), or null if no active position
|
|
40232
|
+
*/
|
|
40233
|
+
this.getPositionActiveMinutes = async (symbol, context) => {
|
|
40234
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, {
|
|
40235
|
+
symbol,
|
|
40236
|
+
context,
|
|
40237
|
+
});
|
|
40238
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40239
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40240
|
+
{
|
|
40241
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40242
|
+
riskName &&
|
|
40243
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
40244
|
+
riskList &&
|
|
40245
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
40246
|
+
actions &&
|
|
40247
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
40248
|
+
}
|
|
40249
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(true, symbol, context);
|
|
40250
|
+
};
|
|
40251
|
+
/**
|
|
40252
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
40253
|
+
*
|
|
40254
|
+
* Returns null if no scheduled signal exists.
|
|
40255
|
+
*
|
|
40256
|
+
* @param symbol - Trading pair symbol
|
|
40257
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
40258
|
+
* @returns Waiting minutes (≥ 0), or null if no scheduled signal
|
|
40259
|
+
*/
|
|
40260
|
+
this.getPositionWaitingMinutes = async (symbol, context) => {
|
|
40261
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES, {
|
|
40262
|
+
symbol,
|
|
40263
|
+
context,
|
|
40264
|
+
});
|
|
40265
|
+
backtest.strategyValidationService.validate(context.strategyName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40266
|
+
backtest.exchangeValidationService.validate(context.exchangeName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40267
|
+
{
|
|
40268
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
40269
|
+
riskName &&
|
|
40270
|
+
backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
40271
|
+
riskList &&
|
|
40272
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
40273
|
+
actions &&
|
|
40274
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, BACKTEST_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
40275
|
+
}
|
|
40276
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(true, symbol, context);
|
|
40277
|
+
};
|
|
39834
40278
|
/**
|
|
39835
40279
|
* Returns the best price reached in the profit direction during this position's life.
|
|
39836
40280
|
*
|
|
@@ -41265,6 +41709,33 @@ class BacktestUtils {
|
|
|
41265
41709
|
});
|
|
41266
41710
|
return await backtest.strategyCoreService.averageBuy(true, symbol, currentPrice, context, cost);
|
|
41267
41711
|
};
|
|
41712
|
+
/**
|
|
41713
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
41714
|
+
*
|
|
41715
|
+
* @param symbol - Trading pair symbol
|
|
41716
|
+
* @param currentPrice - Market price at the time of the call
|
|
41717
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
41718
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
41719
|
+
*
|
|
41720
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
41721
|
+
*
|
|
41722
|
+
* @example
|
|
41723
|
+
* ```typescript
|
|
41724
|
+
* await Backtest.commitSignalNotify("BTCUSDT", 42000, {
|
|
41725
|
+
* strategyName: "my-strategy",
|
|
41726
|
+
* exchangeName: "binance",
|
|
41727
|
+
* frameName: "1h"
|
|
41728
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
41729
|
+
* ```
|
|
41730
|
+
*/
|
|
41731
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
41732
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
41733
|
+
symbol,
|
|
41734
|
+
currentPrice,
|
|
41735
|
+
context,
|
|
41736
|
+
});
|
|
41737
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, context, true);
|
|
41738
|
+
};
|
|
41268
41739
|
/**
|
|
41269
41740
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
41270
41741
|
*
|
|
@@ -41445,6 +41916,8 @@ const LIVE_METHOD_NAME_GET_POSITION_PARTIALS = "LiveUtils.getPositionPartials";
|
|
|
41445
41916
|
const LIVE_METHOD_NAME_GET_POSITION_ENTRIES = "LiveUtils.getPositionEntries";
|
|
41446
41917
|
const LIVE_METHOD_NAME_GET_POSITION_ESTIMATE_MINUTES = "LiveUtils.getPositionEstimateMinutes";
|
|
41447
41918
|
const LIVE_METHOD_NAME_GET_POSITION_COUNTDOWN_MINUTES = "LiveUtils.getPositionCountdownMinutes";
|
|
41919
|
+
const LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "LiveUtils.getPositionActiveMinutes";
|
|
41920
|
+
const LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "LiveUtils.getPositionWaitingMinutes";
|
|
41448
41921
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_PRICE = "LiveUtils.getPositionHighestProfitPrice";
|
|
41449
41922
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "LiveUtils.getPositionHighestProfitTimestamp";
|
|
41450
41923
|
const LIVE_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "LiveUtils.getPositionHighestPnlPercentage";
|
|
@@ -41478,6 +41951,7 @@ const LIVE_METHOD_NAME_TRAILING_STOP_COST = "LiveUtils.commitTrailingStopCost";
|
|
|
41478
41951
|
const LIVE_METHOD_NAME_TRAILING_PROFIT_COST = "LiveUtils.commitTrailingTakeCost";
|
|
41479
41952
|
const LIVE_METHOD_NAME_ACTIVATE_SCHEDULED = "Live.commitActivateScheduled";
|
|
41480
41953
|
const LIVE_METHOD_NAME_AVERAGE_BUY = "Live.commitAverageBuy";
|
|
41954
|
+
const LIVE_METHOD_NAME_SIGNAL_NOTIFY = "Live.commitSignalNotify";
|
|
41481
41955
|
const LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "LiveUtils.hasNoPendingSignal";
|
|
41482
41956
|
const LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "LiveUtils.hasNoScheduledSignal";
|
|
41483
41957
|
/**
|
|
@@ -42478,6 +42952,68 @@ class LiveUtils {
|
|
|
42478
42952
|
frameName: "",
|
|
42479
42953
|
});
|
|
42480
42954
|
};
|
|
42955
|
+
/**
|
|
42956
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
42957
|
+
*
|
|
42958
|
+
* Returns null if no pending signal exists.
|
|
42959
|
+
*
|
|
42960
|
+
* @param symbol - Trading pair symbol
|
|
42961
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
42962
|
+
* @returns Active minutes (≥ 0), or null if no active position
|
|
42963
|
+
*/
|
|
42964
|
+
this.getPositionActiveMinutes = async (symbol, context) => {
|
|
42965
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, {
|
|
42966
|
+
symbol,
|
|
42967
|
+
context,
|
|
42968
|
+
});
|
|
42969
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42970
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42971
|
+
{
|
|
42972
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
42973
|
+
riskName &&
|
|
42974
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
42975
|
+
riskList &&
|
|
42976
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
42977
|
+
actions &&
|
|
42978
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
42979
|
+
}
|
|
42980
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(false, symbol, {
|
|
42981
|
+
strategyName: context.strategyName,
|
|
42982
|
+
exchangeName: context.exchangeName,
|
|
42983
|
+
frameName: "",
|
|
42984
|
+
});
|
|
42985
|
+
};
|
|
42986
|
+
/**
|
|
42987
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
42988
|
+
*
|
|
42989
|
+
* Returns null if no scheduled signal exists.
|
|
42990
|
+
*
|
|
42991
|
+
* @param symbol - Trading pair symbol
|
|
42992
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
42993
|
+
* @returns Waiting minutes (≥ 0), or null if no scheduled signal
|
|
42994
|
+
*/
|
|
42995
|
+
this.getPositionWaitingMinutes = async (symbol, context) => {
|
|
42996
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES, {
|
|
42997
|
+
symbol,
|
|
42998
|
+
context,
|
|
42999
|
+
});
|
|
43000
|
+
backtest.strategyValidationService.validate(context.strategyName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43001
|
+
backtest.exchangeValidationService.validate(context.exchangeName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43002
|
+
{
|
|
43003
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
43004
|
+
riskName &&
|
|
43005
|
+
backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
43006
|
+
riskList &&
|
|
43007
|
+
riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
43008
|
+
actions &&
|
|
43009
|
+
actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, LIVE_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
43010
|
+
}
|
|
43011
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(false, symbol, {
|
|
43012
|
+
strategyName: context.strategyName,
|
|
43013
|
+
exchangeName: context.exchangeName,
|
|
43014
|
+
frameName: "",
|
|
43015
|
+
});
|
|
43016
|
+
};
|
|
42481
43017
|
/**
|
|
42482
43018
|
* Returns the best price reached in the profit direction during this position's life.
|
|
42483
43019
|
*
|
|
@@ -44174,6 +44710,36 @@ class LiveUtils {
|
|
|
44174
44710
|
frameName: "",
|
|
44175
44711
|
}, cost);
|
|
44176
44712
|
};
|
|
44713
|
+
/**
|
|
44714
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
44715
|
+
*
|
|
44716
|
+
* @param symbol - Trading pair symbol
|
|
44717
|
+
* @param currentPrice - Market price at the time of the call
|
|
44718
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
44719
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
44720
|
+
*
|
|
44721
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
44722
|
+
*
|
|
44723
|
+
* @example
|
|
44724
|
+
* ```typescript
|
|
44725
|
+
* await Live.commitSignalNotify("BTCUSDT", 42000, {
|
|
44726
|
+
* strategyName: "my-strategy",
|
|
44727
|
+
* exchangeName: "binance",
|
|
44728
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
44729
|
+
* ```
|
|
44730
|
+
*/
|
|
44731
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
44732
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
44733
|
+
symbol,
|
|
44734
|
+
currentPrice,
|
|
44735
|
+
context,
|
|
44736
|
+
});
|
|
44737
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, {
|
|
44738
|
+
strategyName: context.strategyName,
|
|
44739
|
+
exchangeName: context.exchangeName,
|
|
44740
|
+
frameName: "",
|
|
44741
|
+
}, false);
|
|
44742
|
+
};
|
|
44177
44743
|
/**
|
|
44178
44744
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
44179
44745
|
*
|
|
@@ -47901,7 +48467,7 @@ const LOGGER_SERVICE$2 = new LoggerService();
|
|
|
47901
48467
|
* Default configuration that enables all report services.
|
|
47902
48468
|
* Used when no specific configuration is provided to enable().
|
|
47903
48469
|
*/
|
|
47904
|
-
const WILDCARD_TARGET$
|
|
48470
|
+
const WILDCARD_TARGET$2 = {
|
|
47905
48471
|
backtest: true,
|
|
47906
48472
|
strategy: true,
|
|
47907
48473
|
breakeven: true,
|
|
@@ -47952,7 +48518,7 @@ class ReportUtils {
|
|
|
47952
48518
|
*
|
|
47953
48519
|
* @returns Cleanup function that unsubscribes from all enabled services
|
|
47954
48520
|
*/
|
|
47955
|
-
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$
|
|
48521
|
+
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) => {
|
|
47956
48522
|
LOGGER_SERVICE$2.debug(REPORT_UTILS_METHOD_NAME_ENABLE, {
|
|
47957
48523
|
backtest: bt,
|
|
47958
48524
|
breakeven,
|
|
@@ -48044,7 +48610,7 @@ class ReportUtils {
|
|
|
48044
48610
|
* Report.disable();
|
|
48045
48611
|
* ```
|
|
48046
48612
|
*/
|
|
48047
|
-
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$
|
|
48613
|
+
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) => {
|
|
48048
48614
|
LOGGER_SERVICE$2.debug(REPORT_UTILS_METHOD_NAME_DISABLE, {
|
|
48049
48615
|
backtest: bt,
|
|
48050
48616
|
breakeven,
|
|
@@ -48168,7 +48734,7 @@ const LOGGER_SERVICE$1 = new LoggerService();
|
|
|
48168
48734
|
* Default configuration that enables all markdown services.
|
|
48169
48735
|
* Used when no specific configuration is provided to `enable()`.
|
|
48170
48736
|
*/
|
|
48171
|
-
const WILDCARD_TARGET = {
|
|
48737
|
+
const WILDCARD_TARGET$1 = {
|
|
48172
48738
|
backtest: true,
|
|
48173
48739
|
breakeven: true,
|
|
48174
48740
|
heat: true,
|
|
@@ -48219,7 +48785,7 @@ class MarkdownUtils {
|
|
|
48219
48785
|
*
|
|
48220
48786
|
* @returns Cleanup function that unsubscribes from all enabled services
|
|
48221
48787
|
*/
|
|
48222
|
-
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) => {
|
|
48788
|
+
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) => {
|
|
48223
48789
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_ENABLE, {
|
|
48224
48790
|
backtest: bt,
|
|
48225
48791
|
breakeven,
|
|
@@ -48313,7 +48879,7 @@ class MarkdownUtils {
|
|
|
48313
48879
|
* Markdown.disable();
|
|
48314
48880
|
* ```
|
|
48315
48881
|
*/
|
|
48316
|
-
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) => {
|
|
48882
|
+
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) => {
|
|
48317
48883
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_DISABLE, {
|
|
48318
48884
|
backtest: bt,
|
|
48319
48885
|
breakeven,
|
|
@@ -48368,6 +48934,87 @@ class MarkdownUtils {
|
|
|
48368
48934
|
backtest.maxDrawdownMarkdownService.unsubscribe();
|
|
48369
48935
|
}
|
|
48370
48936
|
};
|
|
48937
|
+
/**
|
|
48938
|
+
* Clears markdown report data selectively.
|
|
48939
|
+
*
|
|
48940
|
+
* Clears accumulated data for specified markdown services without unsubscribing.
|
|
48941
|
+
* Use this method to reset report data for specific services while keeping them active.
|
|
48942
|
+
*
|
|
48943
|
+
* Each cleared service will:
|
|
48944
|
+
* - Clear accumulated data for all reports
|
|
48945
|
+
* - Start fresh with new data for future events
|
|
48946
|
+
* - Not affect event subscriptions or report generation status
|
|
48947
|
+
*
|
|
48948
|
+
* @param config - Service configuration object specifying which services to clear. Defaults to clearing all services.
|
|
48949
|
+
* @param config.backtest - Clear backtest result report data
|
|
48950
|
+
* @param config.breakeven - Clear breakeven event tracking data
|
|
48951
|
+
* @param config.partial - Clear partial profit/loss event tracking data
|
|
48952
|
+
* @param config.heat - Clear portfolio heatmap analysis data
|
|
48953
|
+
* @param config.walker - Clear walker strategy comparison report data
|
|
48954
|
+
* @param config.performance - Clear performance bottleneck analysis data
|
|
48955
|
+
* @param config.risk - Clear risk rejection tracking data
|
|
48956
|
+
* @param config.schedule - Clear scheduled signal tracking data
|
|
48957
|
+
* @param config.live - Clear live trading event report data
|
|
48958
|
+
* @param config.strategy - Clear strategy report data
|
|
48959
|
+
* @param config.sync - Clear sync report data
|
|
48960
|
+
* @param config.highest_profit - Clear highest profit report data
|
|
48961
|
+
* @param config.max_drawdown - Clear max drawdown report data
|
|
48962
|
+
*/
|
|
48963
|
+
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) => {
|
|
48964
|
+
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_CLEAR, {
|
|
48965
|
+
backtest: bt,
|
|
48966
|
+
breakeven,
|
|
48967
|
+
heat,
|
|
48968
|
+
live,
|
|
48969
|
+
partial,
|
|
48970
|
+
performance,
|
|
48971
|
+
risk,
|
|
48972
|
+
strategy,
|
|
48973
|
+
schedule,
|
|
48974
|
+
walker,
|
|
48975
|
+
sync,
|
|
48976
|
+
highest_profit,
|
|
48977
|
+
});
|
|
48978
|
+
if (bt) {
|
|
48979
|
+
backtest.backtestMarkdownService.clear();
|
|
48980
|
+
}
|
|
48981
|
+
if (breakeven) {
|
|
48982
|
+
backtest.breakevenMarkdownService.clear();
|
|
48983
|
+
}
|
|
48984
|
+
if (heat) {
|
|
48985
|
+
backtest.heatMarkdownService.clear();
|
|
48986
|
+
}
|
|
48987
|
+
if (live) {
|
|
48988
|
+
backtest.liveMarkdownService.clear();
|
|
48989
|
+
}
|
|
48990
|
+
if (partial) {
|
|
48991
|
+
backtest.partialMarkdownService.clear();
|
|
48992
|
+
}
|
|
48993
|
+
if (performance) {
|
|
48994
|
+
backtest.performanceMarkdownService.clear();
|
|
48995
|
+
}
|
|
48996
|
+
if (risk) {
|
|
48997
|
+
backtest.riskMarkdownService.clear();
|
|
48998
|
+
}
|
|
48999
|
+
if (strategy) {
|
|
49000
|
+
backtest.strategyMarkdownService.clear();
|
|
49001
|
+
}
|
|
49002
|
+
if (schedule) {
|
|
49003
|
+
backtest.scheduleMarkdownService.clear();
|
|
49004
|
+
}
|
|
49005
|
+
if (walker) {
|
|
49006
|
+
backtest.walkerMarkdownService.clear();
|
|
49007
|
+
}
|
|
49008
|
+
if (sync) {
|
|
49009
|
+
backtest.syncMarkdownService.clear();
|
|
49010
|
+
}
|
|
49011
|
+
if (highest_profit) {
|
|
49012
|
+
backtest.highestProfitMarkdownService.clear();
|
|
49013
|
+
}
|
|
49014
|
+
if (max_drawdown) {
|
|
49015
|
+
backtest.maxDrawdownMarkdownService.clear();
|
|
49016
|
+
}
|
|
49017
|
+
};
|
|
48371
49018
|
}
|
|
48372
49019
|
}
|
|
48373
49020
|
/**
|
|
@@ -48410,15 +49057,6 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
48410
49057
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_USE_JSONL);
|
|
48411
49058
|
MarkdownWriter.useJsonl();
|
|
48412
49059
|
}
|
|
48413
|
-
/**
|
|
48414
|
-
* Clears the memoized storage cache.
|
|
48415
|
-
* Call this when process.cwd() changes between strategy iterations
|
|
48416
|
-
* so new storage instances are created with the updated base path.
|
|
48417
|
-
*/
|
|
48418
|
-
clear() {
|
|
48419
|
-
LOGGER_SERVICE$1.log(MARKDOWN_METHOD_NAME_CLEAR);
|
|
48420
|
-
MarkdownWriter.clear();
|
|
48421
|
-
}
|
|
48422
49060
|
/**
|
|
48423
49061
|
* Switches to a dummy markdown adapter that discards all writes.
|
|
48424
49062
|
* All future markdown writes will be no-ops.
|
|
@@ -49115,6 +49753,7 @@ const SUBJECT_ISOLATION_LIST = [
|
|
|
49115
49753
|
strategyCommitSubject,
|
|
49116
49754
|
syncSubject,
|
|
49117
49755
|
validationSubject,
|
|
49756
|
+
signalNotifySubject,
|
|
49118
49757
|
];
|
|
49119
49758
|
/**
|
|
49120
49759
|
* Creates a snapshot function for a given subject by clearing its internal
|
|
@@ -50733,6 +51372,8 @@ const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_TIMESTAMP = "ReflectUtils.
|
|
|
50733
51372
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_PERCENTAGE = "ReflectUtils.getPositionHighestPnlPercentage";
|
|
50734
51373
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PNL_COST = "ReflectUtils.getPositionHighestPnlCost";
|
|
50735
51374
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_BREAKEVEN = "ReflectUtils.getPositionHighestProfitBreakeven";
|
|
51375
|
+
const REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES = "ReflectUtils.getPositionActiveMinutes";
|
|
51376
|
+
const REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES = "ReflectUtils.getPositionWaitingMinutes";
|
|
50736
51377
|
const REFLECT_METHOD_NAME_GET_POSITION_DRAWDOWN_MINUTES = "ReflectUtils.getPositionDrawdownMinutes";
|
|
50737
51378
|
const REFLECT_METHOD_NAME_GET_POSITION_HIGHEST_PROFIT_MINUTES = "ReflectUtils.getPositionHighestProfitMinutes";
|
|
50738
51379
|
const REFLECT_METHOD_NAME_GET_POSITION_MAX_DRAWDOWN_MINUTES = "ReflectUtils.getPositionMaxDrawdownMinutes";
|
|
@@ -51007,6 +51648,52 @@ class ReflectUtils {
|
|
|
51007
51648
|
}
|
|
51008
51649
|
return await backtest.strategyCoreService.getPositionHighestProfitBreakeven(backtest$1, symbol, context);
|
|
51009
51650
|
};
|
|
51651
|
+
/**
|
|
51652
|
+
* Returns the number of minutes the position has been active since it opened.
|
|
51653
|
+
*
|
|
51654
|
+
* Returns null if no pending signal exists.
|
|
51655
|
+
*
|
|
51656
|
+
* @param symbol - Trading pair symbol
|
|
51657
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
51658
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
51659
|
+
* @returns Promise resolving to active minutes (≥ 0) or null
|
|
51660
|
+
*/
|
|
51661
|
+
this.getPositionActiveMinutes = async (symbol, context, backtest$1 = false) => {
|
|
51662
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES, { symbol, context });
|
|
51663
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51664
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51665
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51666
|
+
{
|
|
51667
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
51668
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES);
|
|
51669
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
51670
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_ACTIVE_MINUTES));
|
|
51671
|
+
}
|
|
51672
|
+
return await backtest.strategyCoreService.getPositionActiveMinutes(backtest$1, symbol, context);
|
|
51673
|
+
};
|
|
51674
|
+
/**
|
|
51675
|
+
* Returns the number of minutes the scheduled signal has been waiting for activation.
|
|
51676
|
+
*
|
|
51677
|
+
* Returns null if no scheduled signal exists.
|
|
51678
|
+
*
|
|
51679
|
+
* @param symbol - Trading pair symbol
|
|
51680
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
51681
|
+
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
51682
|
+
* @returns Promise resolving to waiting minutes (≥ 0) or null
|
|
51683
|
+
*/
|
|
51684
|
+
this.getPositionWaitingMinutes = async (symbol, context, backtest$1 = false) => {
|
|
51685
|
+
backtest.loggerService.info(REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES, { symbol, context });
|
|
51686
|
+
backtest.strategyValidationService.validate(context.strategyName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51687
|
+
backtest.exchangeValidationService.validate(context.exchangeName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51688
|
+
context.frameName && backtest.frameValidationService.validate(context.frameName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51689
|
+
{
|
|
51690
|
+
const { riskName, riskList, actions } = backtest.strategySchemaService.get(context.strategyName);
|
|
51691
|
+
riskName && backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES);
|
|
51692
|
+
riskList && riskList.forEach((riskName) => backtest.riskValidationService.validate(riskName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
51693
|
+
actions && actions.forEach((actionName) => backtest.actionValidationService.validate(actionName, REFLECT_METHOD_NAME_GET_POSITION_WAITING_MINUTES));
|
|
51694
|
+
}
|
|
51695
|
+
return await backtest.strategyCoreService.getPositionWaitingMinutes(backtest$1, symbol, context);
|
|
51696
|
+
};
|
|
51010
51697
|
/**
|
|
51011
51698
|
* Returns the number of minutes elapsed since the highest profit price was recorded.
|
|
51012
51699
|
*
|
|
@@ -53283,6 +53970,23 @@ const StorageLive = new StorageLiveAdapter();
|
|
|
53283
53970
|
*/
|
|
53284
53971
|
const StorageBacktest = new StorageBacktestAdapter();
|
|
53285
53972
|
|
|
53973
|
+
/**
|
|
53974
|
+
* Default configuration that enables all notification types.
|
|
53975
|
+
* Used when no specific configuration is provided to enable().
|
|
53976
|
+
*/
|
|
53977
|
+
const WILDCARD_TARGET = {
|
|
53978
|
+
signal: true,
|
|
53979
|
+
partial_profit: true,
|
|
53980
|
+
partial_loss: true,
|
|
53981
|
+
breakeven: true,
|
|
53982
|
+
strategy_commit: true,
|
|
53983
|
+
signal_sync: true,
|
|
53984
|
+
risk: true,
|
|
53985
|
+
info: true,
|
|
53986
|
+
common_error: true,
|
|
53987
|
+
critical_error: true,
|
|
53988
|
+
validation_error: true,
|
|
53989
|
+
};
|
|
53286
53990
|
/**
|
|
53287
53991
|
* Generates a unique key for notification identification.
|
|
53288
53992
|
* @returns Random string identifier
|
|
@@ -53960,7 +54664,44 @@ const CREATE_VALIDATION_ERROR_NOTIFICATION_FN = (error) => ({
|
|
|
53960
54664
|
message: getErrorMessage(error),
|
|
53961
54665
|
backtest: false,
|
|
53962
54666
|
});
|
|
54667
|
+
/**
|
|
54668
|
+
* Creates a notification model for signal info events.
|
|
54669
|
+
* @param data - The signal info contract data
|
|
54670
|
+
* @returns NotificationModel for signal info event
|
|
54671
|
+
*/
|
|
54672
|
+
const CREATE_SIGNAL_INFO_NOTIFICATION_FN = (data) => ({
|
|
54673
|
+
type: "signal.info",
|
|
54674
|
+
id: CREATE_KEY_FN$2(),
|
|
54675
|
+
timestamp: data.timestamp,
|
|
54676
|
+
backtest: data.backtest,
|
|
54677
|
+
symbol: data.symbol,
|
|
54678
|
+
strategyName: data.strategyName,
|
|
54679
|
+
exchangeName: data.exchangeName,
|
|
54680
|
+
signalId: data.data.id,
|
|
54681
|
+
currentPrice: data.currentPrice,
|
|
54682
|
+
position: data.data.position,
|
|
54683
|
+
priceOpen: data.data.priceOpen,
|
|
54684
|
+
priceTakeProfit: data.data.priceTakeProfit,
|
|
54685
|
+
priceStopLoss: data.data.priceStopLoss,
|
|
54686
|
+
originalPriceTakeProfit: data.data.originalPriceTakeProfit,
|
|
54687
|
+
originalPriceStopLoss: data.data.originalPriceStopLoss,
|
|
54688
|
+
originalPriceOpen: data.data.originalPriceOpen,
|
|
54689
|
+
totalEntries: data.data.totalEntries,
|
|
54690
|
+
totalPartials: data.data.totalPartials,
|
|
54691
|
+
pnl: data.data.pnl,
|
|
54692
|
+
pnlPercentage: data.data.pnl.pnlPercentage,
|
|
54693
|
+
pnlPriceOpen: data.data.pnl.priceOpen,
|
|
54694
|
+
pnlPriceClose: data.data.pnl.priceClose,
|
|
54695
|
+
pnlCost: data.data.pnl.pnlCost,
|
|
54696
|
+
pnlEntries: data.data.pnl.pnlEntries,
|
|
54697
|
+
note: data.note,
|
|
54698
|
+
notificationId: data.notificationId,
|
|
54699
|
+
scheduledAt: data.data.scheduledAt,
|
|
54700
|
+
pendingAt: data.data.pendingAt,
|
|
54701
|
+
createdAt: data.timestamp,
|
|
54702
|
+
});
|
|
53963
54703
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryBacktestUtils.handleSignal";
|
|
54704
|
+
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryBacktestUtils.handleSignalNotify";
|
|
53964
54705
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryBacktestUtils.handlePartialProfit";
|
|
53965
54706
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryBacktestUtils.handlePartialLoss";
|
|
53966
54707
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryBacktestUtils.handleBreakeven";
|
|
@@ -53973,6 +54714,7 @@ const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_VALIDATION_ERROR = "Notifi
|
|
|
53973
54714
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_GET_DATA = "NotificationMemoryBacktestUtils.getData";
|
|
53974
54715
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_DISPOSE = "NotificationMemoryBacktestUtils.dispose";
|
|
53975
54716
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryLiveUtils.handleSignal";
|
|
54717
|
+
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryLiveUtils.handleSignalNotify";
|
|
53976
54718
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryLiveUtils.handlePartialProfit";
|
|
53977
54719
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryLiveUtils.handlePartialLoss";
|
|
53978
54720
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryLiveUtils.handleBreakeven";
|
|
@@ -54001,6 +54743,7 @@ const NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR = "NotificationLiveAdapter.cle
|
|
|
54001
54743
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistBacktestUtils.waitForInit";
|
|
54002
54744
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistBacktestUtils._updateNotifications";
|
|
54003
54745
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistBacktestUtils.handleSignal";
|
|
54746
|
+
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistBacktestUtils.handleSignalNotify";
|
|
54004
54747
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistBacktestUtils.handlePartialProfit";
|
|
54005
54748
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistBacktestUtils.handlePartialLoss";
|
|
54006
54749
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistBacktestUtils.handleBreakeven";
|
|
@@ -54015,6 +54758,7 @@ const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_DISPOSE = "NotificationPersistBa
|
|
|
54015
54758
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistLiveUtils.waitForInit";
|
|
54016
54759
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistLiveUtils._updateNotifications";
|
|
54017
54760
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistLiveUtils.handleSignal";
|
|
54761
|
+
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistLiveUtils.handleSignalNotify";
|
|
54018
54762
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistLiveUtils.handlePartialProfit";
|
|
54019
54763
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistLiveUtils.handlePartialLoss";
|
|
54020
54764
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistLiveUtils.handleBreakeven";
|
|
@@ -54057,6 +54801,12 @@ class NotificationMemoryBacktestUtils {
|
|
|
54057
54801
|
this._addNotification(notification);
|
|
54058
54802
|
}
|
|
54059
54803
|
};
|
|
54804
|
+
this.handleSignalNotify = async (data) => {
|
|
54805
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
54806
|
+
signalId: data.data.id,
|
|
54807
|
+
});
|
|
54808
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
54809
|
+
};
|
|
54060
54810
|
/**
|
|
54061
54811
|
* Handles partial profit availability event.
|
|
54062
54812
|
* @param data - The partial profit contract data
|
|
@@ -54201,6 +54951,8 @@ class NotificationDummyBacktestUtils {
|
|
|
54201
54951
|
*/
|
|
54202
54952
|
this.handleSignal = async () => {
|
|
54203
54953
|
};
|
|
54954
|
+
this.handleSignalNotify = async () => {
|
|
54955
|
+
};
|
|
54204
54956
|
/**
|
|
54205
54957
|
* No-op handler for partial profit event.
|
|
54206
54958
|
*/
|
|
@@ -54308,6 +55060,14 @@ class NotificationPersistBacktestUtils {
|
|
|
54308
55060
|
await this._updateNotifications();
|
|
54309
55061
|
}
|
|
54310
55062
|
};
|
|
55063
|
+
this.handleSignalNotify = async (data) => {
|
|
55064
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55065
|
+
signalId: data.data.id,
|
|
55066
|
+
});
|
|
55067
|
+
await this.waitForInit();
|
|
55068
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55069
|
+
await this._updateNotifications();
|
|
55070
|
+
};
|
|
54311
55071
|
/**
|
|
54312
55072
|
* Handles partial profit availability event.
|
|
54313
55073
|
* @param data - The partial profit contract data
|
|
@@ -54509,6 +55269,12 @@ class NotificationMemoryLiveUtils {
|
|
|
54509
55269
|
this._addNotification(notification);
|
|
54510
55270
|
}
|
|
54511
55271
|
};
|
|
55272
|
+
this.handleSignalNotify = async (data) => {
|
|
55273
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55274
|
+
signalId: data.data.id,
|
|
55275
|
+
});
|
|
55276
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55277
|
+
};
|
|
54512
55278
|
/**
|
|
54513
55279
|
* Handles partial profit availability event.
|
|
54514
55280
|
* @param data - The partial profit contract data
|
|
@@ -54653,6 +55419,8 @@ class NotificationDummyLiveUtils {
|
|
|
54653
55419
|
*/
|
|
54654
55420
|
this.handleSignal = async () => {
|
|
54655
55421
|
};
|
|
55422
|
+
this.handleSignalNotify = async () => {
|
|
55423
|
+
};
|
|
54656
55424
|
/**
|
|
54657
55425
|
* No-op handler for partial profit event.
|
|
54658
55426
|
*/
|
|
@@ -54761,6 +55529,14 @@ class NotificationPersistLiveUtils {
|
|
|
54761
55529
|
await this._updateNotifications();
|
|
54762
55530
|
}
|
|
54763
55531
|
};
|
|
55532
|
+
this.handleSignalNotify = async (data) => {
|
|
55533
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55534
|
+
signalId: data.data.id,
|
|
55535
|
+
});
|
|
55536
|
+
await this.waitForInit();
|
|
55537
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55538
|
+
await this._updateNotifications();
|
|
55539
|
+
};
|
|
54764
55540
|
/**
|
|
54765
55541
|
* Handles partial profit availability event.
|
|
54766
55542
|
* @param data - The partial profit contract data
|
|
@@ -54954,6 +55730,9 @@ class NotificationBacktestAdapter {
|
|
|
54954
55730
|
this.handleSignal = async (data) => {
|
|
54955
55731
|
return await this._notificationBacktestUtils.handleSignal(data);
|
|
54956
55732
|
};
|
|
55733
|
+
this.handleSignalNotify = async (data) => {
|
|
55734
|
+
return await this._notificationBacktestUtils.handleSignalNotify(data);
|
|
55735
|
+
};
|
|
54957
55736
|
/**
|
|
54958
55737
|
* Handles partial profit availability event.
|
|
54959
55738
|
* Proxies call to the underlying notification adapter.
|
|
@@ -55109,6 +55888,9 @@ class NotificationLiveAdapter {
|
|
|
55109
55888
|
this.handleSignal = async (data) => {
|
|
55110
55889
|
return await this._notificationLiveUtils.handleSignal(data);
|
|
55111
55890
|
};
|
|
55891
|
+
this.handleSignalNotify = async (data) => {
|
|
55892
|
+
return await this._notificationLiveUtils.handleSignalNotify(data);
|
|
55893
|
+
};
|
|
55112
55894
|
/**
|
|
55113
55895
|
* Handles partial profit availability event.
|
|
55114
55896
|
* Proxies call to the underlying notification adapter.
|
|
@@ -55260,59 +56042,153 @@ class NotificationAdapter {
|
|
|
55260
56042
|
*
|
|
55261
56043
|
* @returns Cleanup function that unsubscribes from all emitters
|
|
55262
56044
|
*/
|
|
55263
|
-
this.enable = singleshot(() => {
|
|
56045
|
+
this.enable = 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) => {
|
|
55264
56046
|
backtest.loggerService.info(NOTIFICATION_ADAPTER_METHOD_NAME_ENABLE);
|
|
55265
56047
|
let unLive;
|
|
55266
56048
|
let unBacktest;
|
|
55267
56049
|
{
|
|
55268
|
-
const unBacktestSignal = signalBacktestEmitter.subscribe((data) =>
|
|
56050
|
+
const unBacktestSignal = signalBacktestEmitter.subscribe(async (data) => {
|
|
56051
|
+
if (signal) {
|
|
56052
|
+
await NotificationBacktest.handleSignal(data);
|
|
56053
|
+
}
|
|
56054
|
+
});
|
|
55269
56055
|
const unBacktestPartialProfit = partialProfitSubject
|
|
55270
56056
|
.filter(({ backtest }) => backtest)
|
|
55271
|
-
.connect((data) =>
|
|
56057
|
+
.connect(async (data) => {
|
|
56058
|
+
if (partial_profit) {
|
|
56059
|
+
await NotificationBacktest.handlePartialProfit(data);
|
|
56060
|
+
}
|
|
56061
|
+
});
|
|
55272
56062
|
const unBacktestPartialLoss = partialLossSubject
|
|
55273
56063
|
.filter(({ backtest }) => backtest)
|
|
55274
|
-
.connect((data) =>
|
|
56064
|
+
.connect(async (data) => {
|
|
56065
|
+
if (partial_loss) {
|
|
56066
|
+
await NotificationBacktest.handlePartialLoss(data);
|
|
56067
|
+
}
|
|
56068
|
+
});
|
|
55275
56069
|
const unBacktestBreakeven = breakevenSubject
|
|
55276
56070
|
.filter(({ backtest }) => backtest)
|
|
55277
|
-
.connect((data) =>
|
|
56071
|
+
.connect(async (data) => {
|
|
56072
|
+
if (breakeven) {
|
|
56073
|
+
await NotificationBacktest.handleBreakeven(data);
|
|
56074
|
+
}
|
|
56075
|
+
});
|
|
55278
56076
|
const unBacktestStrategyCommit = strategyCommitSubject
|
|
55279
56077
|
.filter(({ backtest }) => backtest)
|
|
55280
|
-
.connect((data) =>
|
|
56078
|
+
.connect(async (data) => {
|
|
56079
|
+
if (strategy_commit) {
|
|
56080
|
+
await NotificationBacktest.handleStrategyCommit(data);
|
|
56081
|
+
}
|
|
56082
|
+
});
|
|
55281
56083
|
const unBacktestSync = syncSubject
|
|
55282
56084
|
.filter(({ backtest }) => backtest)
|
|
55283
|
-
.connect((data) =>
|
|
56085
|
+
.connect(async (data) => {
|
|
56086
|
+
if (signal_sync) {
|
|
56087
|
+
await NotificationBacktest.handleSync(data);
|
|
56088
|
+
}
|
|
56089
|
+
});
|
|
55284
56090
|
const unBacktestRisk = riskSubject
|
|
55285
56091
|
.filter(({ backtest }) => backtest)
|
|
55286
|
-
.connect((data) =>
|
|
55287
|
-
|
|
55288
|
-
|
|
55289
|
-
|
|
55290
|
-
|
|
56092
|
+
.connect(async (data) => {
|
|
56093
|
+
if (risk) {
|
|
56094
|
+
await NotificationBacktest.handleRisk(data);
|
|
56095
|
+
}
|
|
56096
|
+
});
|
|
56097
|
+
const unBacktestError = errorEmitter.subscribe(async (error) => {
|
|
56098
|
+
if (common_error) {
|
|
56099
|
+
await NotificationBacktest.handleError(error);
|
|
56100
|
+
}
|
|
56101
|
+
});
|
|
56102
|
+
const unBacktestExit = exitEmitter.subscribe(async (error) => {
|
|
56103
|
+
if (critical_error) {
|
|
56104
|
+
await NotificationBacktest.handleCriticalError(error);
|
|
56105
|
+
}
|
|
56106
|
+
});
|
|
56107
|
+
const unBacktestValidation = validationSubject.subscribe(async (error) => {
|
|
56108
|
+
if (validation_error) {
|
|
56109
|
+
await NotificationBacktest.handleValidationError(error);
|
|
56110
|
+
}
|
|
56111
|
+
});
|
|
56112
|
+
const unBacktestSignalNotify = signalNotifySubject
|
|
56113
|
+
.filter(({ backtest }) => backtest)
|
|
56114
|
+
.connect(async (data) => {
|
|
56115
|
+
if (info) {
|
|
56116
|
+
await NotificationBacktest.handleSignalNotify(data);
|
|
56117
|
+
}
|
|
56118
|
+
});
|
|
56119
|
+
unBacktest = compose(() => unBacktestSignal(), () => unBacktestPartialProfit(), () => unBacktestPartialLoss(), () => unBacktestBreakeven(), () => unBacktestStrategyCommit(), () => unBacktestSync(), () => unBacktestRisk(), () => unBacktestError(), () => unBacktestExit(), () => unBacktestValidation(), () => unBacktestSignalNotify());
|
|
55291
56120
|
}
|
|
55292
56121
|
{
|
|
55293
|
-
const unLiveSignal = signalLiveEmitter.subscribe((data) =>
|
|
56122
|
+
const unLiveSignal = signalLiveEmitter.subscribe(async (data) => {
|
|
56123
|
+
if (signal) {
|
|
56124
|
+
await NotificationLive.handleSignal(data);
|
|
56125
|
+
}
|
|
56126
|
+
});
|
|
55294
56127
|
const unLivePartialProfit = partialProfitSubject
|
|
55295
56128
|
.filter(({ backtest }) => !backtest)
|
|
55296
|
-
.connect((data) =>
|
|
56129
|
+
.connect(async (data) => {
|
|
56130
|
+
if (partial_profit) {
|
|
56131
|
+
await NotificationLive.handlePartialProfit(data);
|
|
56132
|
+
}
|
|
56133
|
+
});
|
|
55297
56134
|
const unLivePartialLoss = partialLossSubject
|
|
55298
56135
|
.filter(({ backtest }) => !backtest)
|
|
55299
|
-
.connect((data) =>
|
|
56136
|
+
.connect(async (data) => {
|
|
56137
|
+
if (partial_loss) {
|
|
56138
|
+
await NotificationLive.handlePartialLoss(data);
|
|
56139
|
+
}
|
|
56140
|
+
});
|
|
55300
56141
|
const unLiveBreakeven = breakevenSubject
|
|
55301
56142
|
.filter(({ backtest }) => !backtest)
|
|
55302
|
-
.connect((data) =>
|
|
56143
|
+
.connect(async (data) => {
|
|
56144
|
+
if (breakeven) {
|
|
56145
|
+
await NotificationLive.handleBreakeven(data);
|
|
56146
|
+
}
|
|
56147
|
+
});
|
|
55303
56148
|
const unLiveStrategyCommit = strategyCommitSubject
|
|
55304
56149
|
.filter(({ backtest }) => !backtest)
|
|
55305
|
-
.connect((data) =>
|
|
56150
|
+
.connect(async (data) => {
|
|
56151
|
+
if (strategy_commit) {
|
|
56152
|
+
await NotificationLive.handleStrategyCommit(data);
|
|
56153
|
+
}
|
|
56154
|
+
});
|
|
55306
56155
|
const unLiveSync = syncSubject
|
|
55307
56156
|
.filter(({ backtest }) => !backtest)
|
|
55308
|
-
.connect((data) =>
|
|
56157
|
+
.connect(async (data) => {
|
|
56158
|
+
if (signal_sync) {
|
|
56159
|
+
await NotificationLive.handleSync(data);
|
|
56160
|
+
}
|
|
56161
|
+
});
|
|
55309
56162
|
const unLiveRisk = riskSubject
|
|
55310
56163
|
.filter(({ backtest }) => !backtest)
|
|
55311
|
-
.connect((data) =>
|
|
55312
|
-
|
|
55313
|
-
|
|
55314
|
-
|
|
55315
|
-
|
|
56164
|
+
.connect(async (data) => {
|
|
56165
|
+
if (risk) {
|
|
56166
|
+
await NotificationLive.handleRisk(data);
|
|
56167
|
+
}
|
|
56168
|
+
});
|
|
56169
|
+
const unLiveError = errorEmitter.subscribe(async (error) => {
|
|
56170
|
+
if (common_error) {
|
|
56171
|
+
await NotificationLive.handleError(error);
|
|
56172
|
+
}
|
|
56173
|
+
});
|
|
56174
|
+
const unLiveExit = exitEmitter.subscribe(async (error) => {
|
|
56175
|
+
if (critical_error) {
|
|
56176
|
+
await NotificationLive.handleCriticalError(error);
|
|
56177
|
+
}
|
|
56178
|
+
});
|
|
56179
|
+
const unLiveValidation = validationSubject.subscribe(async (error) => {
|
|
56180
|
+
if (validation_error) {
|
|
56181
|
+
await NotificationLive.handleValidationError(error);
|
|
56182
|
+
}
|
|
56183
|
+
});
|
|
56184
|
+
const unLiveSignalNotify = signalNotifySubject
|
|
56185
|
+
.filter(({ backtest }) => !backtest)
|
|
56186
|
+
.connect(async (data) => {
|
|
56187
|
+
if (info) {
|
|
56188
|
+
await NotificationLive.handleSignalNotify(data);
|
|
56189
|
+
}
|
|
56190
|
+
});
|
|
56191
|
+
unLive = compose(() => unLiveSignal(), () => unLivePartialProfit(), () => unLivePartialLoss(), () => unLiveBreakeven(), () => unLiveStrategyCommit(), () => unLiveSync(), () => unLiveRisk(), () => unLiveError(), () => unLiveExit(), () => unLiveValidation(), () => unLiveSignalNotify());
|
|
55316
56192
|
}
|
|
55317
56193
|
return () => {
|
|
55318
56194
|
unLive();
|
|
@@ -55550,11 +56426,17 @@ class CacheFnInstance {
|
|
|
55550
56426
|
return cached;
|
|
55551
56427
|
}
|
|
55552
56428
|
}
|
|
56429
|
+
const value = this.fn(...args);
|
|
55553
56430
|
const newCache = {
|
|
55554
56431
|
when: currentWhen,
|
|
55555
|
-
value
|
|
56432
|
+
value,
|
|
55556
56433
|
};
|
|
55557
56434
|
this._cacheMap.set(key, newCache);
|
|
56435
|
+
if (value && value instanceof Promise) {
|
|
56436
|
+
value.catch(() => {
|
|
56437
|
+
this._cacheMap.delete(key);
|
|
56438
|
+
});
|
|
56439
|
+
}
|
|
55558
56440
|
return newCache;
|
|
55559
56441
|
};
|
|
55560
56442
|
/**
|
|
@@ -56135,7 +57017,7 @@ class IntervalFnInstance {
|
|
|
56135
57017
|
* within the same interval or when `fn` itself returned `null`
|
|
56136
57018
|
* @throws Error if method context, execution context, or interval is missing
|
|
56137
57019
|
*/
|
|
56138
|
-
this.run =
|
|
57020
|
+
this.run = (...args) => {
|
|
56139
57021
|
backtest.loggerService.debug(INTERVAL_METHOD_NAME_RUN, { args });
|
|
56140
57022
|
const step = INTERVAL_MINUTES[this.interval];
|
|
56141
57023
|
{
|
|
@@ -56157,10 +57039,15 @@ class IntervalFnInstance {
|
|
|
56157
57039
|
if (this._stateMap.get(stateKey) === currentAligned) {
|
|
56158
57040
|
return null;
|
|
56159
57041
|
}
|
|
56160
|
-
const result =
|
|
57042
|
+
const result = this.fn.apply(null, args);
|
|
56161
57043
|
if (result !== null) {
|
|
56162
57044
|
this._stateMap.set(stateKey, currentAligned);
|
|
56163
57045
|
}
|
|
57046
|
+
if (result && result instanceof Promise) {
|
|
57047
|
+
result.catch(() => {
|
|
57048
|
+
this._stateMap.delete(stateKey);
|
|
57049
|
+
});
|
|
57050
|
+
}
|
|
56164
57051
|
return result;
|
|
56165
57052
|
};
|
|
56166
57053
|
/**
|
|
@@ -57691,4 +58578,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
57691
58578
|
return !errors.length;
|
|
57692
58579
|
};
|
|
57693
58580
|
|
|
57694
|
-
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRecentAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PersistStorageAdapter, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, Storage, StorageBacktest, StorageLive, Strategy, Sync, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getRawCandles, getRiskSchema, getScheduledSignal, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|
|
58581
|
+
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistCandleAdapter, PersistIntervalAdapter, PersistLogAdapter, PersistMeasureAdapter, PersistMemoryAdapter, PersistNotificationAdapter, PersistPartialAdapter, PersistRecentAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PersistStorageAdapter, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, Storage, StorageBacktest, StorageLive, Strategy, Sync, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenBacktestProgress, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, warmCandles, writeMemory };
|