backtest-kit 6.12.0 → 6.14.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 +1412 -117
- package/build/index.mjs +1404 -118
- package/package.json +2 -2
- package/types.d.ts +657 -9
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,
|
|
@@ -982,6 +992,12 @@ const PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA = "PersistMemoryUtils.listMemor
|
|
|
982
992
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA = "PersistMemoryUtils.hasMemoryData";
|
|
983
993
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR = "PersistMemoryUtils.clear";
|
|
984
994
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE = "PersistMemoryUtils.dispose";
|
|
995
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER = "PersistRecentUtils.usePersistRecentAdapter";
|
|
996
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA = "PersistRecentUtils.readRecentData";
|
|
997
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA = "PersistRecentUtils.writeRecentData";
|
|
998
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON = "PersistRecentUtils.useJson";
|
|
999
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY = "PersistRecentUtils.useDummy";
|
|
1000
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR = "PersistRecentUtils.clear";
|
|
985
1001
|
const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
|
|
986
1002
|
const BASE_UNLINK_RETRY_COUNT = 5;
|
|
987
1003
|
const BASE_UNLINK_RETRY_DELAY = 1000;
|
|
@@ -2828,6 +2844,115 @@ class PersistMemoryUtils {
|
|
|
2828
2844
|
* ```
|
|
2829
2845
|
*/
|
|
2830
2846
|
const PersistMemoryAdapter = new PersistMemoryUtils();
|
|
2847
|
+
/**
|
|
2848
|
+
* Utility class for managing recent signal persistence.
|
|
2849
|
+
*
|
|
2850
|
+
* Features:
|
|
2851
|
+
* - Memoized storage instances per (symbol, strategyName, exchangeName, frameName) context
|
|
2852
|
+
* - Custom adapter support
|
|
2853
|
+
* - Atomic read/write operations
|
|
2854
|
+
* - Crash-safe recent signal state management
|
|
2855
|
+
*
|
|
2856
|
+
* Used by RecentPersistBacktestUtils/RecentPersistLiveUtils for recent signal persistence.
|
|
2857
|
+
*/
|
|
2858
|
+
class PersistRecentUtils {
|
|
2859
|
+
constructor() {
|
|
2860
|
+
this.PersistRecentFactory = PersistBase;
|
|
2861
|
+
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":"), (symbol, strategyName, exchangeName, frameName, backtest) => Reflect.construct(this.PersistRecentFactory, [
|
|
2862
|
+
this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join("_"),
|
|
2863
|
+
`./dump/data/recent/`,
|
|
2864
|
+
]));
|
|
2865
|
+
/**
|
|
2866
|
+
* Reads the latest persisted recent signal for a given context.
|
|
2867
|
+
*
|
|
2868
|
+
* Returns null if no recent signal exists.
|
|
2869
|
+
*
|
|
2870
|
+
* @param symbol - Trading pair symbol
|
|
2871
|
+
* @param strategyName - Strategy identifier
|
|
2872
|
+
* @param exchangeName - Exchange identifier
|
|
2873
|
+
* @param frameName - Frame identifier
|
|
2874
|
+
* @returns Promise resolving to recent signal or null
|
|
2875
|
+
*/
|
|
2876
|
+
this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
2877
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
|
|
2878
|
+
const key = this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":");
|
|
2879
|
+
const isInitial = !this.getStorage.has(key);
|
|
2880
|
+
const stateStorage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
2881
|
+
await stateStorage.waitForInit(isInitial);
|
|
2882
|
+
if (await stateStorage.hasValue(symbol)) {
|
|
2883
|
+
return await stateStorage.readValue(symbol);
|
|
2884
|
+
}
|
|
2885
|
+
return null;
|
|
2886
|
+
};
|
|
2887
|
+
/**
|
|
2888
|
+
* Writes the latest recent signal to disk with atomic file writes.
|
|
2889
|
+
*
|
|
2890
|
+
* Uses symbol as the entity ID within the per-context storage instance.
|
|
2891
|
+
* Uses atomic writes to prevent corruption on crashes.
|
|
2892
|
+
*
|
|
2893
|
+
* @param signalRow - Recent signal data to persist
|
|
2894
|
+
* @param symbol - Trading pair symbol
|
|
2895
|
+
* @param strategyName - Strategy identifier
|
|
2896
|
+
* @param exchangeName - Exchange identifier
|
|
2897
|
+
* @param frameName - Frame identifier
|
|
2898
|
+
* @returns Promise that resolves when write is complete
|
|
2899
|
+
*/
|
|
2900
|
+
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
2901
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2902
|
+
const key = this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":");
|
|
2903
|
+
const isInitial = !this.getStorage.has(key);
|
|
2904
|
+
const stateStorage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
2905
|
+
await stateStorage.waitForInit(isInitial);
|
|
2906
|
+
await stateStorage.writeValue(symbol, signalRow);
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
createKeyParts(symbol, strategyName, exchangeName, frameName, backtest) {
|
|
2910
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
2911
|
+
if (frameName)
|
|
2912
|
+
parts.push(frameName);
|
|
2913
|
+
parts.push(backtest ? "backtest" : "live");
|
|
2914
|
+
return parts;
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Registers a custom persistence adapter.
|
|
2918
|
+
*
|
|
2919
|
+
* @param Ctor - Custom PersistBase constructor
|
|
2920
|
+
*/
|
|
2921
|
+
usePersistRecentAdapter(Ctor) {
|
|
2922
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
|
|
2923
|
+
this.PersistRecentFactory = Ctor;
|
|
2924
|
+
}
|
|
2925
|
+
/**
|
|
2926
|
+
* Clears the memoized storage cache.
|
|
2927
|
+
* Call this when process.cwd() changes between strategy iterations
|
|
2928
|
+
* so new storage instances are created with the updated base path.
|
|
2929
|
+
*/
|
|
2930
|
+
clear() {
|
|
2931
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
|
|
2932
|
+
this.getStorage.clear();
|
|
2933
|
+
}
|
|
2934
|
+
/**
|
|
2935
|
+
* Switches to the default JSON persist adapter.
|
|
2936
|
+
* All future persistence writes will use JSON storage.
|
|
2937
|
+
*/
|
|
2938
|
+
useJson() {
|
|
2939
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
|
|
2940
|
+
this.usePersistRecentAdapter(PersistBase);
|
|
2941
|
+
}
|
|
2942
|
+
/**
|
|
2943
|
+
* Switches to a dummy persist adapter that discards all writes.
|
|
2944
|
+
* All future persistence writes will be no-ops.
|
|
2945
|
+
*/
|
|
2946
|
+
useDummy() {
|
|
2947
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2948
|
+
this.usePersistRecentAdapter(PersistDummy);
|
|
2949
|
+
}
|
|
2950
|
+
}
|
|
2951
|
+
/**
|
|
2952
|
+
* Global singleton instance of PersistRecentUtils.
|
|
2953
|
+
* Used by RecentPersistBacktestUtils/RecentPersistLiveUtils for recent signal persistence.
|
|
2954
|
+
*/
|
|
2955
|
+
const PersistRecentAdapter = new PersistRecentUtils();
|
|
2831
2956
|
|
|
2832
2957
|
var _a$2, _b$2;
|
|
2833
2958
|
const BUSY_DELAY = 100;
|
|
@@ -10155,7 +10280,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
10155
10280
|
* @param backtest - Whether running in backtest mode
|
|
10156
10281
|
* @returns Unique string key for memoization
|
|
10157
10282
|
*/
|
|
10158
|
-
const CREATE_KEY_FN$
|
|
10283
|
+
const CREATE_KEY_FN$v = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10159
10284
|
const parts = [symbol, strategyName, exchangeName];
|
|
10160
10285
|
if (frameName)
|
|
10161
10286
|
parts.push(frameName);
|
|
@@ -10422,7 +10547,7 @@ class StrategyConnectionService {
|
|
|
10422
10547
|
* @param backtest - Whether running in backtest mode
|
|
10423
10548
|
* @returns Configured ClientStrategy instance
|
|
10424
10549
|
*/
|
|
10425
|
-
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
10550
|
+
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$v(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10426
10551
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
10427
10552
|
return new ClientStrategy({
|
|
10428
10553
|
symbol,
|
|
@@ -11343,7 +11468,7 @@ class StrategyConnectionService {
|
|
|
11343
11468
|
}
|
|
11344
11469
|
return;
|
|
11345
11470
|
}
|
|
11346
|
-
const key = CREATE_KEY_FN$
|
|
11471
|
+
const key = CREATE_KEY_FN$v(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
11347
11472
|
if (!this.getStrategy.has(key)) {
|
|
11348
11473
|
return;
|
|
11349
11474
|
}
|
|
@@ -12512,7 +12637,7 @@ class ClientRisk {
|
|
|
12512
12637
|
* @param backtest - Whether running in backtest mode
|
|
12513
12638
|
* @returns Unique string key for memoization
|
|
12514
12639
|
*/
|
|
12515
|
-
const CREATE_KEY_FN$
|
|
12640
|
+
const CREATE_KEY_FN$u = (riskName, exchangeName, frameName, backtest) => {
|
|
12516
12641
|
const parts = [riskName, exchangeName];
|
|
12517
12642
|
if (frameName)
|
|
12518
12643
|
parts.push(frameName);
|
|
@@ -12612,7 +12737,7 @@ class RiskConnectionService {
|
|
|
12612
12737
|
* @param backtest - True if backtest mode, false if live mode
|
|
12613
12738
|
* @returns Configured ClientRisk instance
|
|
12614
12739
|
*/
|
|
12615
|
-
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
12740
|
+
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$u(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
12616
12741
|
const schema = this.riskSchemaService.get(riskName);
|
|
12617
12742
|
return new ClientRisk({
|
|
12618
12743
|
...schema,
|
|
@@ -12681,7 +12806,7 @@ class RiskConnectionService {
|
|
|
12681
12806
|
payload,
|
|
12682
12807
|
});
|
|
12683
12808
|
if (payload) {
|
|
12684
|
-
const key = CREATE_KEY_FN$
|
|
12809
|
+
const key = CREATE_KEY_FN$u(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
12685
12810
|
this.getRisk.clear(key);
|
|
12686
12811
|
}
|
|
12687
12812
|
else {
|
|
@@ -13725,7 +13850,7 @@ class ClientAction {
|
|
|
13725
13850
|
* @param backtest - Whether running in backtest mode
|
|
13726
13851
|
* @returns Unique string key for memoization
|
|
13727
13852
|
*/
|
|
13728
|
-
const CREATE_KEY_FN$
|
|
13853
|
+
const CREATE_KEY_FN$t = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13729
13854
|
const parts = [actionName, strategyName, exchangeName];
|
|
13730
13855
|
if (frameName)
|
|
13731
13856
|
parts.push(frameName);
|
|
@@ -13777,7 +13902,7 @@ class ActionConnectionService {
|
|
|
13777
13902
|
* @param backtest - True if backtest mode, false if live mode
|
|
13778
13903
|
* @returns Configured ClientAction instance
|
|
13779
13904
|
*/
|
|
13780
|
-
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
13905
|
+
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$t(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13781
13906
|
const schema = this.actionSchemaService.get(actionName);
|
|
13782
13907
|
return new ClientAction({
|
|
13783
13908
|
...schema,
|
|
@@ -13988,7 +14113,7 @@ class ActionConnectionService {
|
|
|
13988
14113
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
13989
14114
|
return;
|
|
13990
14115
|
}
|
|
13991
|
-
const key = CREATE_KEY_FN$
|
|
14116
|
+
const key = CREATE_KEY_FN$t(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
13992
14117
|
if (!this.getAction.has(key)) {
|
|
13993
14118
|
return;
|
|
13994
14119
|
}
|
|
@@ -13999,14 +14124,14 @@ class ActionConnectionService {
|
|
|
13999
14124
|
}
|
|
14000
14125
|
}
|
|
14001
14126
|
|
|
14002
|
-
const METHOD_NAME_VALIDATE$
|
|
14127
|
+
const METHOD_NAME_VALIDATE$3 = "exchangeCoreService validate";
|
|
14003
14128
|
/**
|
|
14004
14129
|
* Creates a unique key for memoizing validate calls.
|
|
14005
14130
|
* Key format: "exchangeName"
|
|
14006
14131
|
* @param exchangeName - Exchange name
|
|
14007
14132
|
* @returns Unique string key for memoization
|
|
14008
14133
|
*/
|
|
14009
|
-
const CREATE_KEY_FN$
|
|
14134
|
+
const CREATE_KEY_FN$s = (exchangeName) => {
|
|
14010
14135
|
return exchangeName;
|
|
14011
14136
|
};
|
|
14012
14137
|
/**
|
|
@@ -14030,11 +14155,11 @@ class ExchangeCoreService {
|
|
|
14030
14155
|
* @param exchangeName - Name of the exchange to validate
|
|
14031
14156
|
* @returns Promise that resolves when validation is complete
|
|
14032
14157
|
*/
|
|
14033
|
-
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
14034
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14158
|
+
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$s(exchangeName), async (exchangeName) => {
|
|
14159
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$3, {
|
|
14035
14160
|
exchangeName,
|
|
14036
14161
|
});
|
|
14037
|
-
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$
|
|
14162
|
+
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$3);
|
|
14038
14163
|
});
|
|
14039
14164
|
/**
|
|
14040
14165
|
* Fetches historical candles with execution context.
|
|
@@ -14275,14 +14400,14 @@ class ExchangeCoreService {
|
|
|
14275
14400
|
}
|
|
14276
14401
|
}
|
|
14277
14402
|
|
|
14278
|
-
const METHOD_NAME_VALIDATE$
|
|
14403
|
+
const METHOD_NAME_VALIDATE$2 = "strategyCoreService validate";
|
|
14279
14404
|
/**
|
|
14280
14405
|
* Creates a unique key for memoizing validate calls.
|
|
14281
14406
|
* Key format: "strategyName:exchangeName:frameName"
|
|
14282
14407
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14283
14408
|
* @returns Unique string key for memoization
|
|
14284
14409
|
*/
|
|
14285
|
-
const CREATE_KEY_FN$
|
|
14410
|
+
const CREATE_KEY_FN$r = (context) => {
|
|
14286
14411
|
const parts = [context.strategyName, context.exchangeName];
|
|
14287
14412
|
if (context.frameName)
|
|
14288
14413
|
parts.push(context.frameName);
|
|
@@ -14314,16 +14439,16 @@ class StrategyCoreService {
|
|
|
14314
14439
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14315
14440
|
* @returns Promise that resolves when validation is complete
|
|
14316
14441
|
*/
|
|
14317
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
14318
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
14442
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$r(context), async (context) => {
|
|
14443
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
14319
14444
|
context,
|
|
14320
14445
|
});
|
|
14321
14446
|
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
14322
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$
|
|
14323
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$
|
|
14324
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$
|
|
14325
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14326
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
14447
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$2);
|
|
14448
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$2);
|
|
14449
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$2);
|
|
14450
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2);
|
|
14451
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$2));
|
|
14327
14452
|
});
|
|
14328
14453
|
/**
|
|
14329
14454
|
* Retrieves the currently active pending signal for the symbol.
|
|
@@ -15652,7 +15777,7 @@ class SizingGlobalService {
|
|
|
15652
15777
|
* @param context - Context with riskName, exchangeName, frameName
|
|
15653
15778
|
* @returns Unique string key for memoization
|
|
15654
15779
|
*/
|
|
15655
|
-
const CREATE_KEY_FN$
|
|
15780
|
+
const CREATE_KEY_FN$q = (context) => {
|
|
15656
15781
|
const parts = [context.riskName, context.exchangeName];
|
|
15657
15782
|
if (context.frameName)
|
|
15658
15783
|
parts.push(context.frameName);
|
|
@@ -15678,7 +15803,7 @@ class RiskGlobalService {
|
|
|
15678
15803
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
15679
15804
|
* @returns Promise that resolves when validation is complete
|
|
15680
15805
|
*/
|
|
15681
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
15806
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$q(context), async (context) => {
|
|
15682
15807
|
this.loggerService.log("riskGlobalService validate", {
|
|
15683
15808
|
context,
|
|
15684
15809
|
});
|
|
@@ -15749,14 +15874,14 @@ class RiskGlobalService {
|
|
|
15749
15874
|
}
|
|
15750
15875
|
}
|
|
15751
15876
|
|
|
15752
|
-
const METHOD_NAME_VALIDATE = "actionCoreService validate";
|
|
15877
|
+
const METHOD_NAME_VALIDATE$1 = "actionCoreService validate";
|
|
15753
15878
|
/**
|
|
15754
15879
|
* Creates a unique key for memoizing validate calls.
|
|
15755
15880
|
* Key format: "strategyName:exchangeName:frameName"
|
|
15756
15881
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15757
15882
|
* @returns Unique string key for memoization
|
|
15758
15883
|
*/
|
|
15759
|
-
const CREATE_KEY_FN$
|
|
15884
|
+
const CREATE_KEY_FN$p = (context) => {
|
|
15760
15885
|
const parts = [context.strategyName, context.exchangeName];
|
|
15761
15886
|
if (context.frameName)
|
|
15762
15887
|
parts.push(context.frameName);
|
|
@@ -15800,17 +15925,17 @@ class ActionCoreService {
|
|
|
15800
15925
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
15801
15926
|
* @returns Promise that resolves when all validations complete
|
|
15802
15927
|
*/
|
|
15803
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
15804
|
-
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
15928
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$p(context), async (context) => {
|
|
15929
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
15805
15930
|
context,
|
|
15806
15931
|
});
|
|
15807
15932
|
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
15808
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
15809
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
15810
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
15811
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
15812
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
15813
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
15933
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$1);
|
|
15934
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$1);
|
|
15935
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$1);
|
|
15936
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1);
|
|
15937
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$1));
|
|
15938
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$1));
|
|
15814
15939
|
});
|
|
15815
15940
|
/**
|
|
15816
15941
|
* Initializes all ClientAction instances for the strategy.
|
|
@@ -20843,7 +20968,7 @@ const ReportWriter = new ReportWriterAdapter();
|
|
|
20843
20968
|
* @param backtest - Whether running in backtest mode
|
|
20844
20969
|
* @returns Unique string key for memoization
|
|
20845
20970
|
*/
|
|
20846
|
-
const CREATE_KEY_FN$
|
|
20971
|
+
const CREATE_KEY_FN$o = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
20847
20972
|
const parts = [symbol, strategyName, exchangeName];
|
|
20848
20973
|
if (frameName)
|
|
20849
20974
|
parts.push(frameName);
|
|
@@ -21089,7 +21214,7 @@ class BacktestMarkdownService {
|
|
|
21089
21214
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21090
21215
|
* Each combination gets its own isolated storage instance.
|
|
21091
21216
|
*/
|
|
21092
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21217
|
+
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));
|
|
21093
21218
|
/**
|
|
21094
21219
|
* Processes tick events and accumulates closed signals.
|
|
21095
21220
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -21246,7 +21371,7 @@ class BacktestMarkdownService {
|
|
|
21246
21371
|
payload,
|
|
21247
21372
|
});
|
|
21248
21373
|
if (payload) {
|
|
21249
|
-
const key = CREATE_KEY_FN$
|
|
21374
|
+
const key = CREATE_KEY_FN$o(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
21250
21375
|
this.getStorage.clear(key);
|
|
21251
21376
|
}
|
|
21252
21377
|
else {
|
|
@@ -21308,7 +21433,7 @@ class BacktestMarkdownService {
|
|
|
21308
21433
|
* @param backtest - Whether running in backtest mode
|
|
21309
21434
|
* @returns Unique string key for memoization
|
|
21310
21435
|
*/
|
|
21311
|
-
const CREATE_KEY_FN$
|
|
21436
|
+
const CREATE_KEY_FN$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21312
21437
|
const parts = [symbol, strategyName, exchangeName];
|
|
21313
21438
|
if (frameName)
|
|
21314
21439
|
parts.push(frameName);
|
|
@@ -21803,7 +21928,7 @@ class LiveMarkdownService {
|
|
|
21803
21928
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21804
21929
|
* Each combination gets its own isolated storage instance.
|
|
21805
21930
|
*/
|
|
21806
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21931
|
+
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));
|
|
21807
21932
|
/**
|
|
21808
21933
|
* Subscribes to live signal emitter to receive tick events.
|
|
21809
21934
|
* Protected against multiple subscriptions.
|
|
@@ -22021,7 +22146,7 @@ class LiveMarkdownService {
|
|
|
22021
22146
|
payload,
|
|
22022
22147
|
});
|
|
22023
22148
|
if (payload) {
|
|
22024
|
-
const key = CREATE_KEY_FN$
|
|
22149
|
+
const key = CREATE_KEY_FN$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22025
22150
|
this.getStorage.clear(key);
|
|
22026
22151
|
}
|
|
22027
22152
|
else {
|
|
@@ -22041,7 +22166,7 @@ class LiveMarkdownService {
|
|
|
22041
22166
|
* @param backtest - Whether running in backtest mode
|
|
22042
22167
|
* @returns Unique string key for memoization
|
|
22043
22168
|
*/
|
|
22044
|
-
const CREATE_KEY_FN$
|
|
22169
|
+
const CREATE_KEY_FN$m = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22045
22170
|
const parts = [symbol, strategyName, exchangeName];
|
|
22046
22171
|
if (frameName)
|
|
22047
22172
|
parts.push(frameName);
|
|
@@ -22330,7 +22455,7 @@ class ScheduleMarkdownService {
|
|
|
22330
22455
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22331
22456
|
* Each combination gets its own isolated storage instance.
|
|
22332
22457
|
*/
|
|
22333
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22458
|
+
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));
|
|
22334
22459
|
/**
|
|
22335
22460
|
* Subscribes to signal emitter to receive scheduled signal events.
|
|
22336
22461
|
* Protected against multiple subscriptions.
|
|
@@ -22533,7 +22658,7 @@ class ScheduleMarkdownService {
|
|
|
22533
22658
|
payload,
|
|
22534
22659
|
});
|
|
22535
22660
|
if (payload) {
|
|
22536
|
-
const key = CREATE_KEY_FN$
|
|
22661
|
+
const key = CREATE_KEY_FN$m(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22537
22662
|
this.getStorage.clear(key);
|
|
22538
22663
|
}
|
|
22539
22664
|
else {
|
|
@@ -22553,7 +22678,7 @@ class ScheduleMarkdownService {
|
|
|
22553
22678
|
* @param backtest - Whether running in backtest mode
|
|
22554
22679
|
* @returns Unique string key for memoization
|
|
22555
22680
|
*/
|
|
22556
|
-
const CREATE_KEY_FN$
|
|
22681
|
+
const CREATE_KEY_FN$l = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22557
22682
|
const parts = [symbol, strategyName, exchangeName];
|
|
22558
22683
|
if (frameName)
|
|
22559
22684
|
parts.push(frameName);
|
|
@@ -22798,7 +22923,7 @@ class PerformanceMarkdownService {
|
|
|
22798
22923
|
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22799
22924
|
* Each combination gets its own isolated storage instance.
|
|
22800
22925
|
*/
|
|
22801
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22926
|
+
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));
|
|
22802
22927
|
/**
|
|
22803
22928
|
* Subscribes to performance emitter to receive performance events.
|
|
22804
22929
|
* Protected against multiple subscriptions.
|
|
@@ -22965,7 +23090,7 @@ class PerformanceMarkdownService {
|
|
|
22965
23090
|
payload,
|
|
22966
23091
|
});
|
|
22967
23092
|
if (payload) {
|
|
22968
|
-
const key = CREATE_KEY_FN$
|
|
23093
|
+
const key = CREATE_KEY_FN$l(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22969
23094
|
this.getStorage.clear(key);
|
|
22970
23095
|
}
|
|
22971
23096
|
else {
|
|
@@ -23444,7 +23569,7 @@ class WalkerMarkdownService {
|
|
|
23444
23569
|
* @param backtest - Whether running in backtest mode
|
|
23445
23570
|
* @returns Unique string key for memoization
|
|
23446
23571
|
*/
|
|
23447
|
-
const CREATE_KEY_FN$
|
|
23572
|
+
const CREATE_KEY_FN$k = (exchangeName, frameName, backtest) => {
|
|
23448
23573
|
const parts = [exchangeName];
|
|
23449
23574
|
if (frameName)
|
|
23450
23575
|
parts.push(frameName);
|
|
@@ -23891,7 +24016,7 @@ class HeatMarkdownService {
|
|
|
23891
24016
|
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
23892
24017
|
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
23893
24018
|
*/
|
|
23894
|
-
this.getStorage = memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
24019
|
+
this.getStorage = memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$k(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
|
|
23895
24020
|
/**
|
|
23896
24021
|
* Subscribes to signal emitter to receive tick events.
|
|
23897
24022
|
* Protected against multiple subscriptions.
|
|
@@ -24109,7 +24234,7 @@ class HeatMarkdownService {
|
|
|
24109
24234
|
payload,
|
|
24110
24235
|
});
|
|
24111
24236
|
if (payload) {
|
|
24112
|
-
const key = CREATE_KEY_FN$
|
|
24237
|
+
const key = CREATE_KEY_FN$k(payload.exchangeName, payload.frameName, payload.backtest);
|
|
24113
24238
|
this.getStorage.clear(key);
|
|
24114
24239
|
}
|
|
24115
24240
|
else {
|
|
@@ -25140,7 +25265,7 @@ class ClientPartial {
|
|
|
25140
25265
|
* @param backtest - Whether running in backtest mode
|
|
25141
25266
|
* @returns Unique string key for memoization
|
|
25142
25267
|
*/
|
|
25143
|
-
const CREATE_KEY_FN$
|
|
25268
|
+
const CREATE_KEY_FN$j = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
25144
25269
|
/**
|
|
25145
25270
|
* Creates a callback function for emitting profit events to partialProfitSubject.
|
|
25146
25271
|
*
|
|
@@ -25262,7 +25387,7 @@ class PartialConnectionService {
|
|
|
25262
25387
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
25263
25388
|
* Value: ClientPartial instance with logger and event emitters
|
|
25264
25389
|
*/
|
|
25265
|
-
this.getPartial = memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
25390
|
+
this.getPartial = memoize(([signalId, backtest]) => CREATE_KEY_FN$j(signalId, backtest), (signalId, backtest) => {
|
|
25266
25391
|
return new ClientPartial({
|
|
25267
25392
|
signalId,
|
|
25268
25393
|
logger: this.loggerService,
|
|
@@ -25352,7 +25477,7 @@ class PartialConnectionService {
|
|
|
25352
25477
|
const partial = this.getPartial(data.id, backtest);
|
|
25353
25478
|
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
25354
25479
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
25355
|
-
const key = CREATE_KEY_FN$
|
|
25480
|
+
const key = CREATE_KEY_FN$j(data.id, backtest);
|
|
25356
25481
|
this.getPartial.clear(key);
|
|
25357
25482
|
};
|
|
25358
25483
|
}
|
|
@@ -25368,7 +25493,7 @@ class PartialConnectionService {
|
|
|
25368
25493
|
* @param backtest - Whether running in backtest mode
|
|
25369
25494
|
* @returns Unique string key for memoization
|
|
25370
25495
|
*/
|
|
25371
|
-
const CREATE_KEY_FN$
|
|
25496
|
+
const CREATE_KEY_FN$i = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
25372
25497
|
const parts = [symbol, strategyName, exchangeName];
|
|
25373
25498
|
if (frameName)
|
|
25374
25499
|
parts.push(frameName);
|
|
@@ -25591,7 +25716,7 @@ class PartialMarkdownService {
|
|
|
25591
25716
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
25592
25717
|
* Each combination gets its own isolated storage instance.
|
|
25593
25718
|
*/
|
|
25594
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
25719
|
+
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));
|
|
25595
25720
|
/**
|
|
25596
25721
|
* Subscribes to partial profit/loss signal emitters to receive events.
|
|
25597
25722
|
* Protected against multiple subscriptions.
|
|
@@ -25801,7 +25926,7 @@ class PartialMarkdownService {
|
|
|
25801
25926
|
payload,
|
|
25802
25927
|
});
|
|
25803
25928
|
if (payload) {
|
|
25804
|
-
const key = CREATE_KEY_FN$
|
|
25929
|
+
const key = CREATE_KEY_FN$i(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
25805
25930
|
this.getStorage.clear(key);
|
|
25806
25931
|
}
|
|
25807
25932
|
else {
|
|
@@ -25817,7 +25942,7 @@ class PartialMarkdownService {
|
|
|
25817
25942
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
25818
25943
|
* @returns Unique string key for memoization
|
|
25819
25944
|
*/
|
|
25820
|
-
const CREATE_KEY_FN$
|
|
25945
|
+
const CREATE_KEY_FN$h = (context) => {
|
|
25821
25946
|
const parts = [context.strategyName, context.exchangeName];
|
|
25822
25947
|
if (context.frameName)
|
|
25823
25948
|
parts.push(context.frameName);
|
|
@@ -25891,7 +26016,7 @@ class PartialGlobalService {
|
|
|
25891
26016
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
25892
26017
|
* @param methodName - Name of the calling method for error tracking
|
|
25893
26018
|
*/
|
|
25894
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
26019
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$h(context), (context, methodName) => {
|
|
25895
26020
|
this.loggerService.log("partialGlobalService validate", {
|
|
25896
26021
|
context,
|
|
25897
26022
|
methodName,
|
|
@@ -26346,7 +26471,7 @@ class ClientBreakeven {
|
|
|
26346
26471
|
* @param backtest - Whether running in backtest mode
|
|
26347
26472
|
* @returns Unique string key for memoization
|
|
26348
26473
|
*/
|
|
26349
|
-
const CREATE_KEY_FN$
|
|
26474
|
+
const CREATE_KEY_FN$g = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
26350
26475
|
/**
|
|
26351
26476
|
* Creates a callback function for emitting breakeven events to breakevenSubject.
|
|
26352
26477
|
*
|
|
@@ -26432,7 +26557,7 @@ class BreakevenConnectionService {
|
|
|
26432
26557
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
26433
26558
|
* Value: ClientBreakeven instance with logger and event emitter
|
|
26434
26559
|
*/
|
|
26435
|
-
this.getBreakeven = memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
26560
|
+
this.getBreakeven = memoize(([signalId, backtest]) => CREATE_KEY_FN$g(signalId, backtest), (signalId, backtest) => {
|
|
26436
26561
|
return new ClientBreakeven({
|
|
26437
26562
|
signalId,
|
|
26438
26563
|
logger: this.loggerService,
|
|
@@ -26493,7 +26618,7 @@ class BreakevenConnectionService {
|
|
|
26493
26618
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
26494
26619
|
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
26495
26620
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
26496
|
-
const key = CREATE_KEY_FN$
|
|
26621
|
+
const key = CREATE_KEY_FN$g(data.id, backtest);
|
|
26497
26622
|
this.getBreakeven.clear(key);
|
|
26498
26623
|
};
|
|
26499
26624
|
}
|
|
@@ -26509,7 +26634,7 @@ class BreakevenConnectionService {
|
|
|
26509
26634
|
* @param backtest - Whether running in backtest mode
|
|
26510
26635
|
* @returns Unique string key for memoization
|
|
26511
26636
|
*/
|
|
26512
|
-
const CREATE_KEY_FN$
|
|
26637
|
+
const CREATE_KEY_FN$f = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
26513
26638
|
const parts = [symbol, strategyName, exchangeName];
|
|
26514
26639
|
if (frameName)
|
|
26515
26640
|
parts.push(frameName);
|
|
@@ -26684,7 +26809,7 @@ class BreakevenMarkdownService {
|
|
|
26684
26809
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
26685
26810
|
* Each combination gets its own isolated storage instance.
|
|
26686
26811
|
*/
|
|
26687
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
26812
|
+
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));
|
|
26688
26813
|
/**
|
|
26689
26814
|
* Subscribes to breakeven signal emitter to receive events.
|
|
26690
26815
|
* Protected against multiple subscriptions.
|
|
@@ -26873,7 +26998,7 @@ class BreakevenMarkdownService {
|
|
|
26873
26998
|
payload,
|
|
26874
26999
|
});
|
|
26875
27000
|
if (payload) {
|
|
26876
|
-
const key = CREATE_KEY_FN$
|
|
27001
|
+
const key = CREATE_KEY_FN$f(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
26877
27002
|
this.getStorage.clear(key);
|
|
26878
27003
|
}
|
|
26879
27004
|
else {
|
|
@@ -26889,7 +27014,7 @@ class BreakevenMarkdownService {
|
|
|
26889
27014
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
26890
27015
|
* @returns Unique string key for memoization
|
|
26891
27016
|
*/
|
|
26892
|
-
const CREATE_KEY_FN$
|
|
27017
|
+
const CREATE_KEY_FN$e = (context) => {
|
|
26893
27018
|
const parts = [context.strategyName, context.exchangeName];
|
|
26894
27019
|
if (context.frameName)
|
|
26895
27020
|
parts.push(context.frameName);
|
|
@@ -26963,7 +27088,7 @@ class BreakevenGlobalService {
|
|
|
26963
27088
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
26964
27089
|
* @param methodName - Name of the calling method for error tracking
|
|
26965
27090
|
*/
|
|
26966
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
27091
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$e(context), (context, methodName) => {
|
|
26967
27092
|
this.loggerService.log("breakevenGlobalService validate", {
|
|
26968
27093
|
context,
|
|
26969
27094
|
methodName,
|
|
@@ -27184,7 +27309,7 @@ class ConfigValidationService {
|
|
|
27184
27309
|
* @param backtest - Whether running in backtest mode
|
|
27185
27310
|
* @returns Unique string key for memoization
|
|
27186
27311
|
*/
|
|
27187
|
-
const CREATE_KEY_FN$
|
|
27312
|
+
const CREATE_KEY_FN$d = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27188
27313
|
const parts = [symbol, strategyName, exchangeName];
|
|
27189
27314
|
if (frameName)
|
|
27190
27315
|
parts.push(frameName);
|
|
@@ -27351,7 +27476,7 @@ class RiskMarkdownService {
|
|
|
27351
27476
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27352
27477
|
* Each combination gets its own isolated storage instance.
|
|
27353
27478
|
*/
|
|
27354
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
27479
|
+
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));
|
|
27355
27480
|
/**
|
|
27356
27481
|
* Subscribes to risk rejection emitter to receive rejection events.
|
|
27357
27482
|
* Protected against multiple subscriptions.
|
|
@@ -27540,7 +27665,7 @@ class RiskMarkdownService {
|
|
|
27540
27665
|
payload,
|
|
27541
27666
|
});
|
|
27542
27667
|
if (payload) {
|
|
27543
|
-
const key = CREATE_KEY_FN$
|
|
27668
|
+
const key = CREATE_KEY_FN$d(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27544
27669
|
this.getStorage.clear(key);
|
|
27545
27670
|
}
|
|
27546
27671
|
else {
|
|
@@ -29922,7 +30047,7 @@ class HighestProfitReportService {
|
|
|
29922
30047
|
* @returns Colon-separated key string for memoization
|
|
29923
30048
|
* @internal
|
|
29924
30049
|
*/
|
|
29925
|
-
const CREATE_KEY_FN$
|
|
30050
|
+
const CREATE_KEY_FN$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
29926
30051
|
const parts = [symbol, strategyName, exchangeName];
|
|
29927
30052
|
if (frameName)
|
|
29928
30053
|
parts.push(frameName);
|
|
@@ -30164,7 +30289,7 @@ class StrategyMarkdownService {
|
|
|
30164
30289
|
*
|
|
30165
30290
|
* @internal
|
|
30166
30291
|
*/
|
|
30167
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
30292
|
+
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));
|
|
30168
30293
|
/**
|
|
30169
30294
|
* Records a cancel-scheduled event when a scheduled signal is cancelled.
|
|
30170
30295
|
*
|
|
@@ -30738,7 +30863,7 @@ class StrategyMarkdownService {
|
|
|
30738
30863
|
this.clear = async (payload) => {
|
|
30739
30864
|
this.loggerService.log("strategyMarkdownService clear", { payload });
|
|
30740
30865
|
if (payload) {
|
|
30741
|
-
const key = CREATE_KEY_FN$
|
|
30866
|
+
const key = CREATE_KEY_FN$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
30742
30867
|
this.getStorage.clear(key);
|
|
30743
30868
|
}
|
|
30744
30869
|
else {
|
|
@@ -30846,7 +30971,7 @@ class StrategyMarkdownService {
|
|
|
30846
30971
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
30847
30972
|
* Key format: "symbol:strategyName:exchangeName[:frameName]:backtest|live"
|
|
30848
30973
|
*/
|
|
30849
|
-
const CREATE_KEY_FN$
|
|
30974
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30850
30975
|
const parts = [symbol, strategyName, exchangeName];
|
|
30851
30976
|
if (frameName)
|
|
30852
30977
|
parts.push(frameName);
|
|
@@ -31039,7 +31164,7 @@ let ReportStorage$2 = class ReportStorage {
|
|
|
31039
31164
|
class SyncMarkdownService {
|
|
31040
31165
|
constructor() {
|
|
31041
31166
|
this.loggerService = inject(TYPES.loggerService);
|
|
31042
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31167
|
+
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));
|
|
31043
31168
|
/**
|
|
31044
31169
|
* Subscribes to `syncSubject` to start receiving `SignalSyncContract` events.
|
|
31045
31170
|
* Protected against multiple subscriptions via `singleshot` — subsequent calls
|
|
@@ -31235,7 +31360,7 @@ class SyncMarkdownService {
|
|
|
31235
31360
|
this.clear = async (payload) => {
|
|
31236
31361
|
this.loggerService.log("syncMarkdownService clear", { payload });
|
|
31237
31362
|
if (payload) {
|
|
31238
|
-
const key = CREATE_KEY_FN$
|
|
31363
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31239
31364
|
this.getStorage.clear(key);
|
|
31240
31365
|
}
|
|
31241
31366
|
else {
|
|
@@ -31248,7 +31373,7 @@ class SyncMarkdownService {
|
|
|
31248
31373
|
/**
|
|
31249
31374
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31250
31375
|
*/
|
|
31251
|
-
const CREATE_KEY_FN$
|
|
31376
|
+
const CREATE_KEY_FN$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31252
31377
|
const parts = [symbol, strategyName, exchangeName];
|
|
31253
31378
|
if (frameName)
|
|
31254
31379
|
parts.push(frameName);
|
|
@@ -31424,7 +31549,7 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
31424
31549
|
class HighestProfitMarkdownService {
|
|
31425
31550
|
constructor() {
|
|
31426
31551
|
this.loggerService = inject(TYPES.loggerService);
|
|
31427
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31552
|
+
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));
|
|
31428
31553
|
/**
|
|
31429
31554
|
* Subscribes to `highestProfitSubject` to start receiving `HighestProfitContract`
|
|
31430
31555
|
* events. Protected against multiple subscriptions via `singleshot` — subsequent
|
|
@@ -31590,7 +31715,7 @@ class HighestProfitMarkdownService {
|
|
|
31590
31715
|
this.clear = async (payload) => {
|
|
31591
31716
|
this.loggerService.log("highestProfitMarkdownService clear", { payload });
|
|
31592
31717
|
if (payload) {
|
|
31593
|
-
const key = CREATE_KEY_FN$
|
|
31718
|
+
const key = CREATE_KEY_FN$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31594
31719
|
this.getStorage.clear(key);
|
|
31595
31720
|
}
|
|
31596
31721
|
else {
|
|
@@ -31612,7 +31737,7 @@ const LISTEN_TIMEOUT$1 = 120000;
|
|
|
31612
31737
|
* @param backtest - Whether running in backtest mode
|
|
31613
31738
|
* @returns Unique string key for memoization
|
|
31614
31739
|
*/
|
|
31615
|
-
const CREATE_KEY_FN$
|
|
31740
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31616
31741
|
const parts = [symbol, strategyName, exchangeName];
|
|
31617
31742
|
if (frameName)
|
|
31618
31743
|
parts.push(frameName);
|
|
@@ -31655,7 +31780,7 @@ class PriceMetaService {
|
|
|
31655
31780
|
* Each subject holds the latest currentPrice emitted by the strategy iterator for that key.
|
|
31656
31781
|
* Instances are cached until clear() is called.
|
|
31657
31782
|
*/
|
|
31658
|
-
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31783
|
+
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
31659
31784
|
/**
|
|
31660
31785
|
* Returns the current market price for the given symbol and context.
|
|
31661
31786
|
*
|
|
@@ -31684,10 +31809,10 @@ class PriceMetaService {
|
|
|
31684
31809
|
if (source.data) {
|
|
31685
31810
|
return source.data;
|
|
31686
31811
|
}
|
|
31687
|
-
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$
|
|
31812
|
+
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...`);
|
|
31688
31813
|
const currentPrice = await waitForNext(source, (data) => !!data, LISTEN_TIMEOUT$1);
|
|
31689
31814
|
if (typeof currentPrice === "symbol") {
|
|
31690
|
-
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$
|
|
31815
|
+
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$9(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31691
31816
|
}
|
|
31692
31817
|
return currentPrice;
|
|
31693
31818
|
};
|
|
@@ -31729,7 +31854,7 @@ class PriceMetaService {
|
|
|
31729
31854
|
this.getSource.clear();
|
|
31730
31855
|
return;
|
|
31731
31856
|
}
|
|
31732
|
-
const key = CREATE_KEY_FN$
|
|
31857
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31733
31858
|
this.getSource.clear(key);
|
|
31734
31859
|
};
|
|
31735
31860
|
}
|
|
@@ -31747,7 +31872,7 @@ const LISTEN_TIMEOUT = 120000;
|
|
|
31747
31872
|
* @param backtest - Whether running in backtest mode
|
|
31748
31873
|
* @returns Unique string key for memoization
|
|
31749
31874
|
*/
|
|
31750
|
-
const CREATE_KEY_FN$
|
|
31875
|
+
const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31751
31876
|
const parts = [symbol, strategyName, exchangeName];
|
|
31752
31877
|
if (frameName)
|
|
31753
31878
|
parts.push(frameName);
|
|
@@ -31790,7 +31915,7 @@ class TimeMetaService {
|
|
|
31790
31915
|
* Each subject holds the latest createdAt timestamp emitted by the strategy iterator for that key.
|
|
31791
31916
|
* Instances are cached until clear() is called.
|
|
31792
31917
|
*/
|
|
31793
|
-
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31918
|
+
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
31794
31919
|
/**
|
|
31795
31920
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
31796
31921
|
*
|
|
@@ -31818,10 +31943,10 @@ class TimeMetaService {
|
|
|
31818
31943
|
if (source.data) {
|
|
31819
31944
|
return source.data;
|
|
31820
31945
|
}
|
|
31821
|
-
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$
|
|
31946
|
+
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...`);
|
|
31822
31947
|
const timestamp = await waitForNext(source, (data) => !!data, LISTEN_TIMEOUT);
|
|
31823
31948
|
if (typeof timestamp === "symbol") {
|
|
31824
|
-
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$
|
|
31949
|
+
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31825
31950
|
}
|
|
31826
31951
|
return timestamp;
|
|
31827
31952
|
};
|
|
@@ -31863,7 +31988,7 @@ class TimeMetaService {
|
|
|
31863
31988
|
this.getSource.clear();
|
|
31864
31989
|
return;
|
|
31865
31990
|
}
|
|
31866
|
-
const key = CREATE_KEY_FN$
|
|
31991
|
+
const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31867
31992
|
this.getSource.clear(key);
|
|
31868
31993
|
};
|
|
31869
31994
|
}
|
|
@@ -31959,7 +32084,7 @@ class MaxDrawdownReportService {
|
|
|
31959
32084
|
/**
|
|
31960
32085
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31961
32086
|
*/
|
|
31962
|
-
const CREATE_KEY_FN$
|
|
32087
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31963
32088
|
const parts = [symbol, strategyName, exchangeName];
|
|
31964
32089
|
if (frameName)
|
|
31965
32090
|
parts.push(frameName);
|
|
@@ -32083,7 +32208,7 @@ class ReportStorage {
|
|
|
32083
32208
|
class MaxDrawdownMarkdownService {
|
|
32084
32209
|
constructor() {
|
|
32085
32210
|
this.loggerService = inject(TYPES.loggerService);
|
|
32086
|
-
this.getStorage = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32211
|
+
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));
|
|
32087
32212
|
/**
|
|
32088
32213
|
* Subscribes to `maxDrawdownSubject` to start receiving `MaxDrawdownContract`
|
|
32089
32214
|
* events. Protected against multiple subscriptions via `singleshot`.
|
|
@@ -32162,7 +32287,7 @@ class MaxDrawdownMarkdownService {
|
|
|
32162
32287
|
this.clear = async (payload) => {
|
|
32163
32288
|
this.loggerService.log("maxDrawdownMarkdownService clear", { payload });
|
|
32164
32289
|
if (payload) {
|
|
32165
|
-
const key = CREATE_KEY_FN$
|
|
32290
|
+
const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32166
32291
|
this.getStorage.clear(key);
|
|
32167
32292
|
}
|
|
32168
32293
|
else {
|
|
@@ -32172,6 +32297,125 @@ class MaxDrawdownMarkdownService {
|
|
|
32172
32297
|
}
|
|
32173
32298
|
}
|
|
32174
32299
|
|
|
32300
|
+
const METHOD_NAME_COMMIT_SIGNAL_NOTIFY = "notificationHelperService.commitSignalNotify";
|
|
32301
|
+
const METHOD_NAME_VALIDATE = "notificationHelperService.validate";
|
|
32302
|
+
/**
|
|
32303
|
+
* Creates a unique key for memoizing validate calls.
|
|
32304
|
+
* Key format: "strategyName:exchangeName:frameName"
|
|
32305
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
32306
|
+
* @returns Unique string key for memoization
|
|
32307
|
+
*/
|
|
32308
|
+
const CREATE_KEY_FN$6 = (context) => {
|
|
32309
|
+
const parts = [context.strategyName, context.exchangeName];
|
|
32310
|
+
if (context.frameName)
|
|
32311
|
+
parts.push(context.frameName);
|
|
32312
|
+
return parts.join(":");
|
|
32313
|
+
};
|
|
32314
|
+
/**
|
|
32315
|
+
* Helper service for emitting signal info notifications.
|
|
32316
|
+
*
|
|
32317
|
+
* Handles validation (memoized per context) and emission of `signal.info` events
|
|
32318
|
+
* via `signalNotifySubject`. Used internally by the framework action pipeline —
|
|
32319
|
+
* end users interact with this via `commitSignalNotify()` in `onActivePing` callbacks.
|
|
32320
|
+
*/
|
|
32321
|
+
class NotificationHelperService {
|
|
32322
|
+
constructor() {
|
|
32323
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
32324
|
+
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
32325
|
+
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
32326
|
+
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
32327
|
+
this.exchangeValidationService = inject(TYPES.exchangeValidationService);
|
|
32328
|
+
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
32329
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
32330
|
+
this.strategyCoreService = inject(TYPES.strategyCoreService);
|
|
32331
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
32332
|
+
/**
|
|
32333
|
+
* Validates strategy, exchange, frame, risk, and action schemas for the given context.
|
|
32334
|
+
*
|
|
32335
|
+
* Memoized per unique `"strategyName:exchangeName[:frameName]"` key — subsequent calls
|
|
32336
|
+
* with the same context are no-ops, so validation runs at most once per context.
|
|
32337
|
+
*
|
|
32338
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32339
|
+
* @throws {Error} If any registered schema fails validation
|
|
32340
|
+
*/
|
|
32341
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$6(context), async (context) => {
|
|
32342
|
+
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
32343
|
+
context,
|
|
32344
|
+
});
|
|
32345
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
32346
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE);
|
|
32347
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
32348
|
+
context.frameName &&
|
|
32349
|
+
this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE);
|
|
32350
|
+
riskName &&
|
|
32351
|
+
this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
32352
|
+
riskList &&
|
|
32353
|
+
riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
32354
|
+
actions &&
|
|
32355
|
+
actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE));
|
|
32356
|
+
});
|
|
32357
|
+
/**
|
|
32358
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
32359
|
+
*
|
|
32360
|
+
* Validates all schemas (via memoized `validate`), resolves the pending signal
|
|
32361
|
+
* for the given symbol, then emits a `SignalInfoContract` via `signalNotifySubject`,
|
|
32362
|
+
* which is routed to all registered `listenSignalNotify` callbacks and persisted
|
|
32363
|
+
* by `NotificationAdapter`.
|
|
32364
|
+
*
|
|
32365
|
+
* @param payload - Optional notification fields (notificationId, notificationNote)
|
|
32366
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
32367
|
+
* @param currentPrice - Market price at the time of the call
|
|
32368
|
+
* @param context - Routing context: strategyName, exchangeName, frameName
|
|
32369
|
+
* @param backtest - true when called during a backtest run
|
|
32370
|
+
*
|
|
32371
|
+
* @throws {Error} If no active pending signal is found for the given symbol
|
|
32372
|
+
*
|
|
32373
|
+
* @example
|
|
32374
|
+
* ```typescript
|
|
32375
|
+
* // Inside onActivePing callback:
|
|
32376
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
32377
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
32378
|
+
* notificationId: "msg-123",
|
|
32379
|
+
* });
|
|
32380
|
+
* ```
|
|
32381
|
+
*/
|
|
32382
|
+
this.commitSignalNotify = async (payload, symbol, currentPrice, context, backtest) => {
|
|
32383
|
+
this.loggerService.info(METHOD_NAME_COMMIT_SIGNAL_NOTIFY, {
|
|
32384
|
+
symbol,
|
|
32385
|
+
context,
|
|
32386
|
+
backtest,
|
|
32387
|
+
currentPrice,
|
|
32388
|
+
});
|
|
32389
|
+
this.validate(context);
|
|
32390
|
+
const pendingSignal = await this.strategyCoreService.getPendingSignal(backtest, symbol, currentPrice, {
|
|
32391
|
+
strategyName: context.strategyName,
|
|
32392
|
+
exchangeName: context.exchangeName,
|
|
32393
|
+
frameName: "",
|
|
32394
|
+
});
|
|
32395
|
+
if (!pendingSignal) {
|
|
32396
|
+
throw new Error(`SignalUtils notify No pending signal found symbol=${symbol} `);
|
|
32397
|
+
}
|
|
32398
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, {
|
|
32399
|
+
strategyName: context.strategyName,
|
|
32400
|
+
exchangeName: context.exchangeName,
|
|
32401
|
+
frameName: context.frameName,
|
|
32402
|
+
}, backtest);
|
|
32403
|
+
await signalNotifySubject.next({
|
|
32404
|
+
backtest,
|
|
32405
|
+
symbol,
|
|
32406
|
+
currentPrice,
|
|
32407
|
+
data: pendingSignal,
|
|
32408
|
+
exchangeName: context.exchangeName,
|
|
32409
|
+
strategyName: context.strategyName,
|
|
32410
|
+
frameName: context.frameName,
|
|
32411
|
+
note: payload.notificationNote || pendingSignal.note,
|
|
32412
|
+
notificationId: payload.notificationId,
|
|
32413
|
+
timestamp,
|
|
32414
|
+
});
|
|
32415
|
+
};
|
|
32416
|
+
}
|
|
32417
|
+
}
|
|
32418
|
+
|
|
32175
32419
|
{
|
|
32176
32420
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
32177
32421
|
}
|
|
@@ -32260,6 +32504,9 @@ class MaxDrawdownMarkdownService {
|
|
|
32260
32504
|
provide(TYPES.highestProfitReportService, () => new HighestProfitReportService());
|
|
32261
32505
|
provide(TYPES.maxDrawdownReportService, () => new MaxDrawdownReportService());
|
|
32262
32506
|
}
|
|
32507
|
+
{
|
|
32508
|
+
provide(TYPES.notificationHelperService, () => new NotificationHelperService());
|
|
32509
|
+
}
|
|
32263
32510
|
{
|
|
32264
32511
|
provide(TYPES.exchangeValidationService, () => new ExchangeValidationService());
|
|
32265
32512
|
provide(TYPES.strategyValidationService, () => new StrategyValidationService());
|
|
@@ -32360,6 +32607,9 @@ const reportServices = {
|
|
|
32360
32607
|
highestProfitReportService: inject(TYPES.highestProfitReportService),
|
|
32361
32608
|
maxDrawdownReportService: inject(TYPES.maxDrawdownReportService),
|
|
32362
32609
|
};
|
|
32610
|
+
const helperServices = {
|
|
32611
|
+
notificationHelperService: inject(TYPES.notificationHelperService),
|
|
32612
|
+
};
|
|
32363
32613
|
const validationServices = {
|
|
32364
32614
|
exchangeValidationService: inject(TYPES.exchangeValidationService),
|
|
32365
32615
|
strategyValidationService: inject(TYPES.strategyValidationService),
|
|
@@ -32385,6 +32635,7 @@ const backtest = {
|
|
|
32385
32635
|
...markdownServices,
|
|
32386
32636
|
...reportServices,
|
|
32387
32637
|
...validationServices,
|
|
32638
|
+
...helperServices,
|
|
32388
32639
|
};
|
|
32389
32640
|
init();
|
|
32390
32641
|
|
|
@@ -35301,6 +35552,7 @@ const GET_POSITION_ENTRY_OVERLAP_METHOD_NAME = "strategy.getPositionEntryOverlap
|
|
|
35301
35552
|
const GET_POSITION_PARTIAL_OVERLAP_METHOD_NAME = "strategy.getPositionPartialOverlap";
|
|
35302
35553
|
const HAS_NO_PENDING_SIGNAL_METHOD_NAME = "strategy.hasNoPendingSignal";
|
|
35303
35554
|
const HAS_NO_SCHEDULED_SIGNAL_METHOD_NAME = "strategy.hasNoScheduledSignal";
|
|
35555
|
+
const COMMIT_SIGNAL_NOTIFY_METHOD_NAME = "strategy.commitSignalNotify";
|
|
35304
35556
|
/**
|
|
35305
35557
|
* Cancels the scheduled signal without stopping the strategy.
|
|
35306
35558
|
*
|
|
@@ -37265,6 +37517,50 @@ async function hasNoScheduledSignal(symbol) {
|
|
|
37265
37517
|
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37266
37518
|
return await not(backtest.strategyCoreService.hasScheduledSignal(isBacktest, symbol, { exchangeName, frameName, strategyName }));
|
|
37267
37519
|
}
|
|
37520
|
+
/**
|
|
37521
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
37522
|
+
*
|
|
37523
|
+
* Broadcasts a user-defined informational note without affecting position state.
|
|
37524
|
+
* Useful for annotating strategy decisions, triggering external alerts, or logging
|
|
37525
|
+
* mid-position events (e.g. RSI crossing a threshold, volume spike detected).
|
|
37526
|
+
*
|
|
37527
|
+
* Automatically reads backtest/live mode from execution context.
|
|
37528
|
+
* Automatically reads strategyName, exchangeName, frameName from method context.
|
|
37529
|
+
* Automatically fetches current price via getAveragePrice.
|
|
37530
|
+
*
|
|
37531
|
+
* @param symbol - Trading pair symbol (e.g. "BTCUSDT")
|
|
37532
|
+
* @param payload - Optional notification fields
|
|
37533
|
+
* @param payload.notificationNote - Human-readable note. Falls back to signal.note if omitted.
|
|
37534
|
+
* @param payload.notificationId - Optional correlation ID for external systems (e.g. Telegram message ID).
|
|
37535
|
+
*
|
|
37536
|
+
* @throws {Error} If called outside an execution context
|
|
37537
|
+
* @throws {Error} If called outside a method context
|
|
37538
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
37539
|
+
*
|
|
37540
|
+
* @example
|
|
37541
|
+
* ```typescript
|
|
37542
|
+
* import { commitSignalNotify } from "backtest-kit";
|
|
37543
|
+
*
|
|
37544
|
+
* // Inside onActivePing callback:
|
|
37545
|
+
* await commitSignalNotify("BTCUSDT", {
|
|
37546
|
+
* notificationNote: "RSI crossed 70, consider closing",
|
|
37547
|
+
* notificationId: "msg-123",
|
|
37548
|
+
* });
|
|
37549
|
+
* ```
|
|
37550
|
+
*/
|
|
37551
|
+
async function commitSignalNotify(symbol, payload = {}) {
|
|
37552
|
+
backtest.loggerService.info(COMMIT_SIGNAL_NOTIFY_METHOD_NAME, { symbol, payload });
|
|
37553
|
+
if (!ExecutionContextService.hasContext()) {
|
|
37554
|
+
throw new Error("commitSignalNotify requires an execution context");
|
|
37555
|
+
}
|
|
37556
|
+
if (!MethodContextService.hasContext()) {
|
|
37557
|
+
throw new Error("commitSignalNotify requires a method context");
|
|
37558
|
+
}
|
|
37559
|
+
const currentPrice = await getAveragePrice(symbol);
|
|
37560
|
+
const { backtest: isBacktest } = backtest.executionContextService.context;
|
|
37561
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
37562
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, { strategyName, exchangeName, frameName }, isBacktest);
|
|
37563
|
+
}
|
|
37268
37564
|
|
|
37269
37565
|
const STOP_STRATEGY_METHOD_NAME = "control.stopStrategy";
|
|
37270
37566
|
/**
|
|
@@ -37348,6 +37644,8 @@ const LISTEN_HIGHEST_PROFIT_METHOD_NAME = "event.listenHighestProfit";
|
|
|
37348
37644
|
const LISTEN_HIGHEST_PROFIT_ONCE_METHOD_NAME = "event.listenHighestProfitOnce";
|
|
37349
37645
|
const LISTEN_MAX_DRAWDOWN_METHOD_NAME = "event.listenMaxDrawdown";
|
|
37350
37646
|
const LISTEN_MAX_DRAWDOWN_ONCE_METHOD_NAME = "event.listenMaxDrawdownOnce";
|
|
37647
|
+
const LISTEN_SIGNAL_NOTIFY_METHOD_NAME = "event.listenSignalNotify";
|
|
37648
|
+
const LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME = "event.listenSignalNotifyOnce";
|
|
37351
37649
|
/**
|
|
37352
37650
|
* Subscribes to all signal events with queued async processing.
|
|
37353
37651
|
*
|
|
@@ -38739,6 +39037,46 @@ function listenMaxDrawdownOnce(filterFn, fn) {
|
|
|
38739
39037
|
};
|
|
38740
39038
|
return disposeFn = listenMaxDrawdown(wrappedFn);
|
|
38741
39039
|
}
|
|
39040
|
+
/**
|
|
39041
|
+
* Subscribes to signal info events with queued async processing.
|
|
39042
|
+
* Emits when a strategy calls commitSignalInfo() to broadcast a user-defined note for an open position.
|
|
39043
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
39044
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
39045
|
+
* @param fn - Callback function to handle signal info events
|
|
39046
|
+
* @return Unsubscribe function to stop listening to events
|
|
39047
|
+
*/
|
|
39048
|
+
function listenSignalNotify(fn) {
|
|
39049
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_METHOD_NAME);
|
|
39050
|
+
const wrappedFn = async (event) => {
|
|
39051
|
+
if (await backtest.strategyCoreService.hasPendingSignal(event.backtest, event.symbol, {
|
|
39052
|
+
strategyName: event.strategyName,
|
|
39053
|
+
exchangeName: event.exchangeName,
|
|
39054
|
+
frameName: event.frameName,
|
|
39055
|
+
})) {
|
|
39056
|
+
await fn(event);
|
|
39057
|
+
}
|
|
39058
|
+
};
|
|
39059
|
+
return signalNotifySubject.subscribe(queued(wrappedFn));
|
|
39060
|
+
}
|
|
39061
|
+
/**
|
|
39062
|
+
* Subscribes to filtered signal info events with one-time execution.
|
|
39063
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
39064
|
+
* and automatically unsubscribes.
|
|
39065
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
39066
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
39067
|
+
* @return Unsubscribe function to cancel the listener before it fires
|
|
39068
|
+
*/
|
|
39069
|
+
function listenSignalNotifyOnce(filterFn, fn) {
|
|
39070
|
+
backtest.loggerService.log(LISTEN_SIGNAL_NOTIFY_ONCE_METHOD_NAME);
|
|
39071
|
+
let disposeFn;
|
|
39072
|
+
const wrappedFn = async (event) => {
|
|
39073
|
+
if (filterFn(event)) {
|
|
39074
|
+
await fn(event);
|
|
39075
|
+
disposeFn && disposeFn();
|
|
39076
|
+
}
|
|
39077
|
+
};
|
|
39078
|
+
return disposeFn = listenSignalNotify(wrappedFn);
|
|
39079
|
+
}
|
|
38742
39080
|
|
|
38743
39081
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
38744
39082
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
@@ -38795,6 +39133,7 @@ const BACKTEST_METHOD_NAME_TRAILING_STOP_COST = "BacktestUtils.commitTrailingSto
|
|
|
38795
39133
|
const BACKTEST_METHOD_NAME_TRAILING_PROFIT_COST = "BacktestUtils.commitTrailingTakeCost";
|
|
38796
39134
|
const BACKTEST_METHOD_NAME_ACTIVATE_SCHEDULED = "Backtest.commitActivateScheduled";
|
|
38797
39135
|
const BACKTEST_METHOD_NAME_AVERAGE_BUY = "Backtest.commitAverageBuy";
|
|
39136
|
+
const BACKTEST_METHOD_NAME_SIGNAL_NOTIFY = "Backtest.commitSignalNotify";
|
|
38798
39137
|
const BACKTEST_METHOD_NAME_GET_DATA = "BacktestUtils.getData";
|
|
38799
39138
|
const BACKTEST_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "BacktestUtils.hasNoPendingSignal";
|
|
38800
39139
|
const BACKTEST_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "BacktestUtils.hasNoScheduledSignal";
|
|
@@ -41150,6 +41489,33 @@ class BacktestUtils {
|
|
|
41150
41489
|
});
|
|
41151
41490
|
return await backtest.strategyCoreService.averageBuy(true, symbol, currentPrice, context, cost);
|
|
41152
41491
|
};
|
|
41492
|
+
/**
|
|
41493
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
41494
|
+
*
|
|
41495
|
+
* @param symbol - Trading pair symbol
|
|
41496
|
+
* @param currentPrice - Market price at the time of the call
|
|
41497
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
41498
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
41499
|
+
*
|
|
41500
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
41501
|
+
*
|
|
41502
|
+
* @example
|
|
41503
|
+
* ```typescript
|
|
41504
|
+
* await Backtest.commitSignalNotify("BTCUSDT", 42000, {
|
|
41505
|
+
* strategyName: "my-strategy",
|
|
41506
|
+
* exchangeName: "binance",
|
|
41507
|
+
* frameName: "1h"
|
|
41508
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
41509
|
+
* ```
|
|
41510
|
+
*/
|
|
41511
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
41512
|
+
backtest.loggerService.info(BACKTEST_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
41513
|
+
symbol,
|
|
41514
|
+
currentPrice,
|
|
41515
|
+
context,
|
|
41516
|
+
});
|
|
41517
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, context, true);
|
|
41518
|
+
};
|
|
41153
41519
|
/**
|
|
41154
41520
|
* Gets statistical data from all closed signals for a symbol-strategy pair.
|
|
41155
41521
|
*
|
|
@@ -41363,6 +41729,7 @@ const LIVE_METHOD_NAME_TRAILING_STOP_COST = "LiveUtils.commitTrailingStopCost";
|
|
|
41363
41729
|
const LIVE_METHOD_NAME_TRAILING_PROFIT_COST = "LiveUtils.commitTrailingTakeCost";
|
|
41364
41730
|
const LIVE_METHOD_NAME_ACTIVATE_SCHEDULED = "Live.commitActivateScheduled";
|
|
41365
41731
|
const LIVE_METHOD_NAME_AVERAGE_BUY = "Live.commitAverageBuy";
|
|
41732
|
+
const LIVE_METHOD_NAME_SIGNAL_NOTIFY = "Live.commitSignalNotify";
|
|
41366
41733
|
const LIVE_METHOD_NAME_HAS_NO_PENDING_SIGNAL = "LiveUtils.hasNoPendingSignal";
|
|
41367
41734
|
const LIVE_METHOD_NAME_HAS_NO_SCHEDULED_SIGNAL = "LiveUtils.hasNoScheduledSignal";
|
|
41368
41735
|
/**
|
|
@@ -44059,6 +44426,36 @@ class LiveUtils {
|
|
|
44059
44426
|
frameName: "",
|
|
44060
44427
|
}, cost);
|
|
44061
44428
|
};
|
|
44429
|
+
/**
|
|
44430
|
+
* Emits a `signal.info` notification for the currently active pending signal.
|
|
44431
|
+
*
|
|
44432
|
+
* @param symbol - Trading pair symbol
|
|
44433
|
+
* @param currentPrice - Market price at the time of the call
|
|
44434
|
+
* @param context - Execution context with strategyName and exchangeName
|
|
44435
|
+
* @param payload - Optional notification fields (notificationNote, notificationId)
|
|
44436
|
+
*
|
|
44437
|
+
* @throws {Error} If no active pending signal exists for the given symbol
|
|
44438
|
+
*
|
|
44439
|
+
* @example
|
|
44440
|
+
* ```typescript
|
|
44441
|
+
* await Live.commitSignalNotify("BTCUSDT", 42000, {
|
|
44442
|
+
* strategyName: "my-strategy",
|
|
44443
|
+
* exchangeName: "binance",
|
|
44444
|
+
* }, { notificationNote: "RSI crossed 70" });
|
|
44445
|
+
* ```
|
|
44446
|
+
*/
|
|
44447
|
+
this.commitSignalNotify = async (symbol, currentPrice, context, payload = {}) => {
|
|
44448
|
+
backtest.loggerService.info(LIVE_METHOD_NAME_SIGNAL_NOTIFY, {
|
|
44449
|
+
symbol,
|
|
44450
|
+
currentPrice,
|
|
44451
|
+
context,
|
|
44452
|
+
});
|
|
44453
|
+
await backtest.notificationHelperService.commitSignalNotify(payload, symbol, currentPrice, {
|
|
44454
|
+
strategyName: context.strategyName,
|
|
44455
|
+
exchangeName: context.exchangeName,
|
|
44456
|
+
frameName: "",
|
|
44457
|
+
}, false);
|
|
44458
|
+
};
|
|
44062
44459
|
/**
|
|
44063
44460
|
* Gets statistical data from all live trading events for a symbol-strategy pair.
|
|
44064
44461
|
*
|
|
@@ -45228,6 +45625,503 @@ async function listRiskSchema() {
|
|
|
45228
45625
|
return await backtest.riskValidationService.list();
|
|
45229
45626
|
}
|
|
45230
45627
|
|
|
45628
|
+
const RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistBacktestUtils.handleActivePing";
|
|
45629
|
+
const RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistBacktestUtils.getLatestSignal";
|
|
45630
|
+
const RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistLiveUtils.handleActivePing";
|
|
45631
|
+
const RECENT_PERSIST_LIVE_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistLiveUtils.getLatestSignal";
|
|
45632
|
+
const RECENT_MEMORY_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentMemoryBacktestUtils.handleActivePing";
|
|
45633
|
+
const RECENT_MEMORY_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentMemoryBacktestUtils.getLatestSignal";
|
|
45634
|
+
const RECENT_MEMORY_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentMemoryLiveUtils.handleActivePing";
|
|
45635
|
+
const RECENT_MEMORY_LIVE_METHOD_NAME_GET_LATEST_SIGNAL = "RecentMemoryLiveUtils.getLatestSignal";
|
|
45636
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentBacktestAdapter.handleActivePing";
|
|
45637
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentBacktestAdapter.getLatestSignal";
|
|
45638
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER = "RecentBacktestAdapter.useRecentAdapter";
|
|
45639
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST = "RecentBacktestAdapter.usePersist";
|
|
45640
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY = "RecentBacktestAdapter.useMemory";
|
|
45641
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR = "RecentBacktestAdapter.clear";
|
|
45642
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentLiveAdapter.handleActivePing";
|
|
45643
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentLiveAdapter.getLatestSignal";
|
|
45644
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER = "RecentLiveAdapter.useRecentAdapter";
|
|
45645
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST = "RecentLiveAdapter.usePersist";
|
|
45646
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY = "RecentLiveAdapter.useMemory";
|
|
45647
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR = "RecentLiveAdapter.clear";
|
|
45648
|
+
const RECENT_ADAPTER_METHOD_NAME_ENABLE = "RecentAdapter.enable";
|
|
45649
|
+
const RECENT_ADAPTER_METHOD_NAME_DISABLE = "RecentAdapter.disable";
|
|
45650
|
+
const RECENT_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentAdapter.getLatestSignal";
|
|
45651
|
+
/**
|
|
45652
|
+
* Builds a composite storage key from context parts.
|
|
45653
|
+
* Includes backtest flag as the last segment to prevent live/backtest collisions.
|
|
45654
|
+
* @param symbol - Trading pair symbol
|
|
45655
|
+
* @param strategyName - Strategy identifier
|
|
45656
|
+
* @param exchangeName - Exchange identifier
|
|
45657
|
+
* @param frameName - Frame identifier
|
|
45658
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45659
|
+
* @returns Composite key string
|
|
45660
|
+
*/
|
|
45661
|
+
const CREATE_KEY_FN$5 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
45662
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
45663
|
+
if (frameName)
|
|
45664
|
+
parts.push(frameName);
|
|
45665
|
+
parts.push(backtest ? "backtest" : "live");
|
|
45666
|
+
return parts.join(":");
|
|
45667
|
+
};
|
|
45668
|
+
/**
|
|
45669
|
+
* Persistent storage adapter for backtest recent signals.
|
|
45670
|
+
*
|
|
45671
|
+
* Features:
|
|
45672
|
+
* - Persists the latest active signal per context to disk using PersistRecentAdapter
|
|
45673
|
+
* - Handles active ping events only
|
|
45674
|
+
*
|
|
45675
|
+
* Use this adapter for backtest recent signal persistence across sessions.
|
|
45676
|
+
*/
|
|
45677
|
+
class RecentPersistBacktestUtils {
|
|
45678
|
+
constructor() {
|
|
45679
|
+
/**
|
|
45680
|
+
* Handles active ping event.
|
|
45681
|
+
* Persists the latest signal to disk via PersistRecentAdapter.
|
|
45682
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45683
|
+
*/
|
|
45684
|
+
this.handleActivePing = async (event) => {
|
|
45685
|
+
backtest.loggerService.info(RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45686
|
+
signalId: event.data.id,
|
|
45687
|
+
});
|
|
45688
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45689
|
+
};
|
|
45690
|
+
/**
|
|
45691
|
+
* Retrieves the latest persisted signal for the given context.
|
|
45692
|
+
* @param symbol - Trading pair symbol
|
|
45693
|
+
* @param strategyName - Strategy identifier
|
|
45694
|
+
* @param exchangeName - Exchange identifier
|
|
45695
|
+
* @param frameName - Frame identifier
|
|
45696
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45697
|
+
* @returns The latest signal or null if not found
|
|
45698
|
+
*/
|
|
45699
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45700
|
+
backtest.loggerService.info(RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45701
|
+
symbol,
|
|
45702
|
+
strategyName,
|
|
45703
|
+
exchangeName,
|
|
45704
|
+
frameName,
|
|
45705
|
+
backtest: backtest$1,
|
|
45706
|
+
});
|
|
45707
|
+
return await PersistRecentAdapter.readRecentData(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45708
|
+
};
|
|
45709
|
+
}
|
|
45710
|
+
}
|
|
45711
|
+
/**
|
|
45712
|
+
* In-memory storage adapter for backtest recent signals.
|
|
45713
|
+
*
|
|
45714
|
+
* Features:
|
|
45715
|
+
* - Stores the latest active signal per context key in memory only
|
|
45716
|
+
* - Fast read/write operations
|
|
45717
|
+
* - Data is lost when application restarts
|
|
45718
|
+
*
|
|
45719
|
+
* Use this adapter for testing or when persistence is not required.
|
|
45720
|
+
*/
|
|
45721
|
+
class RecentMemoryBacktestUtils {
|
|
45722
|
+
constructor() {
|
|
45723
|
+
/** Map of composite context keys to the latest signal */
|
|
45724
|
+
this._signals = new Map();
|
|
45725
|
+
/**
|
|
45726
|
+
* Handles active ping event.
|
|
45727
|
+
* Stores the latest signal in memory under the composite context key.
|
|
45728
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45729
|
+
*/
|
|
45730
|
+
this.handleActivePing = async (event) => {
|
|
45731
|
+
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45732
|
+
signalId: event.data.id,
|
|
45733
|
+
});
|
|
45734
|
+
const key = CREATE_KEY_FN$5(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45735
|
+
this._signals.set(key, event.data);
|
|
45736
|
+
};
|
|
45737
|
+
/**
|
|
45738
|
+
* Retrieves the latest in-memory signal for the given context.
|
|
45739
|
+
* @param symbol - Trading pair symbol
|
|
45740
|
+
* @param strategyName - Strategy identifier
|
|
45741
|
+
* @param exchangeName - Exchange identifier
|
|
45742
|
+
* @param frameName - Frame identifier
|
|
45743
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45744
|
+
* @returns The latest signal or null if not found
|
|
45745
|
+
*/
|
|
45746
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45747
|
+
const key = CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45748
|
+
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
45749
|
+
return this._signals.get(key) ?? null;
|
|
45750
|
+
};
|
|
45751
|
+
}
|
|
45752
|
+
}
|
|
45753
|
+
/**
|
|
45754
|
+
* Persistent storage adapter for live recent signals.
|
|
45755
|
+
*
|
|
45756
|
+
* Features:
|
|
45757
|
+
* - Persists the latest active signal per context to disk using PersistRecentAdapter
|
|
45758
|
+
* - Handles active ping events only
|
|
45759
|
+
*
|
|
45760
|
+
* Use this adapter (default) for live recent signal persistence across sessions.
|
|
45761
|
+
*/
|
|
45762
|
+
class RecentPersistLiveUtils {
|
|
45763
|
+
constructor() {
|
|
45764
|
+
/**
|
|
45765
|
+
* Handles active ping event.
|
|
45766
|
+
* Persists the latest signal to disk via PersistRecentAdapter.
|
|
45767
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45768
|
+
*/
|
|
45769
|
+
this.handleActivePing = async (event) => {
|
|
45770
|
+
backtest.loggerService.info(RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45771
|
+
signalId: event.data.id,
|
|
45772
|
+
});
|
|
45773
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45774
|
+
};
|
|
45775
|
+
/**
|
|
45776
|
+
* Retrieves the latest persisted signal for the given context.
|
|
45777
|
+
* @param symbol - Trading pair symbol
|
|
45778
|
+
* @param strategyName - Strategy identifier
|
|
45779
|
+
* @param exchangeName - Exchange identifier
|
|
45780
|
+
* @param frameName - Frame identifier
|
|
45781
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45782
|
+
* @returns The latest signal or null if not found
|
|
45783
|
+
*/
|
|
45784
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45785
|
+
backtest.loggerService.info(RECENT_PERSIST_LIVE_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45786
|
+
symbol,
|
|
45787
|
+
strategyName,
|
|
45788
|
+
exchangeName,
|
|
45789
|
+
frameName,
|
|
45790
|
+
backtest: backtest$1,
|
|
45791
|
+
});
|
|
45792
|
+
return await PersistRecentAdapter.readRecentData(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45793
|
+
};
|
|
45794
|
+
}
|
|
45795
|
+
}
|
|
45796
|
+
/**
|
|
45797
|
+
* In-memory storage adapter for live recent signals.
|
|
45798
|
+
*
|
|
45799
|
+
* Features:
|
|
45800
|
+
* - Stores the latest active signal per context key in memory only
|
|
45801
|
+
* - Fast read/write operations
|
|
45802
|
+
* - Data is lost when application restarts
|
|
45803
|
+
*
|
|
45804
|
+
* Use this adapter for testing or when persistence is not required.
|
|
45805
|
+
*/
|
|
45806
|
+
class RecentMemoryLiveUtils {
|
|
45807
|
+
constructor() {
|
|
45808
|
+
/** Map of composite context keys to the latest signal */
|
|
45809
|
+
this._signals = new Map();
|
|
45810
|
+
/**
|
|
45811
|
+
* Handles active ping event.
|
|
45812
|
+
* Stores the latest signal in memory under the composite context key.
|
|
45813
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45814
|
+
*/
|
|
45815
|
+
this.handleActivePing = async (event) => {
|
|
45816
|
+
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45817
|
+
signalId: event.data.id,
|
|
45818
|
+
});
|
|
45819
|
+
const key = CREATE_KEY_FN$5(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45820
|
+
this._signals.set(key, event.data);
|
|
45821
|
+
};
|
|
45822
|
+
/**
|
|
45823
|
+
* Retrieves the latest in-memory signal for the given context.
|
|
45824
|
+
* @param symbol - Trading pair symbol
|
|
45825
|
+
* @param strategyName - Strategy identifier
|
|
45826
|
+
* @param exchangeName - Exchange identifier
|
|
45827
|
+
* @param frameName - Frame identifier
|
|
45828
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45829
|
+
* @returns The latest signal or null if not found
|
|
45830
|
+
*/
|
|
45831
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45832
|
+
const key = CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45833
|
+
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
45834
|
+
return this._signals.get(key) ?? null;
|
|
45835
|
+
};
|
|
45836
|
+
}
|
|
45837
|
+
}
|
|
45838
|
+
/**
|
|
45839
|
+
* Backtest recent signal adapter with pluggable storage backend.
|
|
45840
|
+
*
|
|
45841
|
+
* Features:
|
|
45842
|
+
* - Adapter pattern for swappable storage implementations
|
|
45843
|
+
* - Default adapter: RecentMemoryBacktestUtils (in-memory storage)
|
|
45844
|
+
* - Alternative adapter: RecentPersistBacktestUtils
|
|
45845
|
+
* - Convenience methods: usePersist(), useMemory()
|
|
45846
|
+
*/
|
|
45847
|
+
class RecentBacktestAdapter {
|
|
45848
|
+
constructor() {
|
|
45849
|
+
/** Internal storage utils instance */
|
|
45850
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45851
|
+
/**
|
|
45852
|
+
* Handles active ping event.
|
|
45853
|
+
* Proxies call to the underlying storage adapter.
|
|
45854
|
+
* @param event - Active ping contract with signal data
|
|
45855
|
+
*/
|
|
45856
|
+
this.handleActivePing = async (event) => {
|
|
45857
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45858
|
+
signalId: event.data.id,
|
|
45859
|
+
});
|
|
45860
|
+
return await this._recentBacktestUtils.handleActivePing(event);
|
|
45861
|
+
};
|
|
45862
|
+
/**
|
|
45863
|
+
* Retrieves the latest signal for the given context.
|
|
45864
|
+
* Proxies call to the underlying storage adapter.
|
|
45865
|
+
* @param symbol - Trading pair symbol
|
|
45866
|
+
* @param strategyName - Strategy identifier
|
|
45867
|
+
* @param exchangeName - Exchange identifier
|
|
45868
|
+
* @param frameName - Frame identifier
|
|
45869
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45870
|
+
* @returns The latest signal or null if not found
|
|
45871
|
+
*/
|
|
45872
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45873
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45874
|
+
symbol,
|
|
45875
|
+
strategyName,
|
|
45876
|
+
exchangeName,
|
|
45877
|
+
frameName,
|
|
45878
|
+
backtest: backtest$1,
|
|
45879
|
+
});
|
|
45880
|
+
return await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45881
|
+
};
|
|
45882
|
+
/**
|
|
45883
|
+
* Sets the storage adapter constructor.
|
|
45884
|
+
* All future storage operations will use this adapter.
|
|
45885
|
+
* @param Ctor - Constructor for recent adapter
|
|
45886
|
+
*/
|
|
45887
|
+
this.useRecentAdapter = (Ctor) => {
|
|
45888
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
|
|
45889
|
+
this._recentBacktestUtils = Reflect.construct(Ctor, []);
|
|
45890
|
+
};
|
|
45891
|
+
/**
|
|
45892
|
+
* Switches to persistent storage adapter.
|
|
45893
|
+
* Signals will be persisted to disk.
|
|
45894
|
+
*/
|
|
45895
|
+
this.usePersist = () => {
|
|
45896
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
45897
|
+
this._recentBacktestUtils = new RecentPersistBacktestUtils();
|
|
45898
|
+
};
|
|
45899
|
+
/**
|
|
45900
|
+
* Switches to in-memory storage adapter (default).
|
|
45901
|
+
* Signals will be stored in memory only.
|
|
45902
|
+
*/
|
|
45903
|
+
this.useMemory = () => {
|
|
45904
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
|
|
45905
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45906
|
+
};
|
|
45907
|
+
/**
|
|
45908
|
+
* Clears the cached utils instance by resetting to the default in-memory adapter.
|
|
45909
|
+
*/
|
|
45910
|
+
this.clear = () => {
|
|
45911
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
|
|
45912
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45913
|
+
};
|
|
45914
|
+
}
|
|
45915
|
+
}
|
|
45916
|
+
/**
|
|
45917
|
+
* Live recent signal adapter with pluggable storage backend.
|
|
45918
|
+
*
|
|
45919
|
+
* Features:
|
|
45920
|
+
* - Adapter pattern for swappable storage implementations
|
|
45921
|
+
* - Default adapter: RecentPersistLiveUtils (persistent storage)
|
|
45922
|
+
* - Alternative adapter: RecentMemoryLiveUtils
|
|
45923
|
+
* - Convenience methods: usePersist(), useMemory()
|
|
45924
|
+
*/
|
|
45925
|
+
class RecentLiveAdapter {
|
|
45926
|
+
constructor() {
|
|
45927
|
+
/** Internal storage utils instance */
|
|
45928
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45929
|
+
/**
|
|
45930
|
+
* Handles active ping event.
|
|
45931
|
+
* Proxies call to the underlying storage adapter.
|
|
45932
|
+
* @param event - Active ping contract with signal data
|
|
45933
|
+
*/
|
|
45934
|
+
this.handleActivePing = async (event) => {
|
|
45935
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45936
|
+
signalId: event.data.id,
|
|
45937
|
+
});
|
|
45938
|
+
return await this._recentLiveUtils.handleActivePing(event);
|
|
45939
|
+
};
|
|
45940
|
+
/**
|
|
45941
|
+
* Retrieves the latest signal for the given context.
|
|
45942
|
+
* Proxies call to the underlying storage adapter.
|
|
45943
|
+
* @param symbol - Trading pair symbol
|
|
45944
|
+
* @param strategyName - Strategy identifier
|
|
45945
|
+
* @param exchangeName - Exchange identifier
|
|
45946
|
+
* @param frameName - Frame identifier
|
|
45947
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45948
|
+
* @returns The latest signal or null if not found
|
|
45949
|
+
*/
|
|
45950
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45951
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45952
|
+
symbol,
|
|
45953
|
+
strategyName,
|
|
45954
|
+
exchangeName,
|
|
45955
|
+
frameName,
|
|
45956
|
+
backtest: backtest$1,
|
|
45957
|
+
});
|
|
45958
|
+
return await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45959
|
+
};
|
|
45960
|
+
/**
|
|
45961
|
+
* Sets the storage adapter constructor.
|
|
45962
|
+
* All future storage operations will use this adapter.
|
|
45963
|
+
* @param Ctor - Constructor for recent adapter
|
|
45964
|
+
*/
|
|
45965
|
+
this.useRecentAdapter = (Ctor) => {
|
|
45966
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
|
|
45967
|
+
this._recentLiveUtils = Reflect.construct(Ctor, []);
|
|
45968
|
+
};
|
|
45969
|
+
/**
|
|
45970
|
+
* Switches to persistent storage adapter (default).
|
|
45971
|
+
* Signals will be persisted to disk.
|
|
45972
|
+
*/
|
|
45973
|
+
this.usePersist = () => {
|
|
45974
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
45975
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45976
|
+
};
|
|
45977
|
+
/**
|
|
45978
|
+
* Switches to in-memory storage adapter.
|
|
45979
|
+
* Signals will be stored in memory only.
|
|
45980
|
+
*/
|
|
45981
|
+
this.useMemory = () => {
|
|
45982
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
|
|
45983
|
+
this._recentLiveUtils = new RecentMemoryLiveUtils();
|
|
45984
|
+
};
|
|
45985
|
+
/**
|
|
45986
|
+
* Clears the cached utils instance by resetting to the default persistent adapter.
|
|
45987
|
+
*/
|
|
45988
|
+
this.clear = () => {
|
|
45989
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR);
|
|
45990
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45991
|
+
};
|
|
45992
|
+
}
|
|
45993
|
+
}
|
|
45994
|
+
/**
|
|
45995
|
+
* Main recent signal adapter that manages both backtest and live recent signal storage.
|
|
45996
|
+
*
|
|
45997
|
+
* Features:
|
|
45998
|
+
* - Subscribes to activePingSubject for automatic storage updates
|
|
45999
|
+
* - Provides unified access to the latest signal for any context
|
|
46000
|
+
* - Singleshot enable pattern prevents duplicate subscriptions
|
|
46001
|
+
* - Cleanup function for proper unsubscription
|
|
46002
|
+
*/
|
|
46003
|
+
class RecentAdapter {
|
|
46004
|
+
constructor() {
|
|
46005
|
+
/**
|
|
46006
|
+
* Enables recent signal storage by subscribing to activePingSubject.
|
|
46007
|
+
* Uses singleshot to ensure one-time subscription.
|
|
46008
|
+
*
|
|
46009
|
+
* @returns Cleanup function that unsubscribes from all emitters
|
|
46010
|
+
*/
|
|
46011
|
+
this.enable = singleshot(() => {
|
|
46012
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_ENABLE);
|
|
46013
|
+
let unBacktest;
|
|
46014
|
+
let unLive;
|
|
46015
|
+
{
|
|
46016
|
+
const unBacktestPingActive = activePingSubject
|
|
46017
|
+
.filter(({ backtest }) => backtest)
|
|
46018
|
+
.connect((event) => RecentBacktest.handleActivePing(event));
|
|
46019
|
+
unBacktest = compose(() => unBacktestPingActive());
|
|
46020
|
+
}
|
|
46021
|
+
{
|
|
46022
|
+
const unLivePingActive = activePingSubject
|
|
46023
|
+
.filter(({ backtest }) => !backtest)
|
|
46024
|
+
.connect((event) => RecentLive.handleActivePing(event));
|
|
46025
|
+
unLive = compose(() => unLivePingActive());
|
|
46026
|
+
}
|
|
46027
|
+
const unEnable = () => this.enable.clear();
|
|
46028
|
+
return compose(() => unBacktest(), () => unLive(), () => unEnable());
|
|
46029
|
+
});
|
|
46030
|
+
/**
|
|
46031
|
+
* Disables recent signal storage by unsubscribing from all emitters.
|
|
46032
|
+
* Safe to call multiple times.
|
|
46033
|
+
*/
|
|
46034
|
+
this.disable = () => {
|
|
46035
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_DISABLE);
|
|
46036
|
+
if (this.enable.hasValue()) {
|
|
46037
|
+
const lastSubscription = this.enable();
|
|
46038
|
+
lastSubscription();
|
|
46039
|
+
}
|
|
46040
|
+
};
|
|
46041
|
+
/**
|
|
46042
|
+
* Retrieves the latest active signal for the given symbol and context.
|
|
46043
|
+
* Searches backtest storage first, then live storage.
|
|
46044
|
+
*
|
|
46045
|
+
* @param symbol - Trading pair symbol
|
|
46046
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
46047
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
46048
|
+
* @returns The latest signal or null if not found
|
|
46049
|
+
* @throws Error if RecentAdapter is not enabled
|
|
46050
|
+
*/
|
|
46051
|
+
this.getLatestSignal = async (symbol, context) => {
|
|
46052
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
46053
|
+
symbol,
|
|
46054
|
+
context,
|
|
46055
|
+
});
|
|
46056
|
+
if (!this.enable.hasValue()) {
|
|
46057
|
+
throw new Error("RecentAdapter is not enabled. Call enable() first.");
|
|
46058
|
+
}
|
|
46059
|
+
let result = null;
|
|
46060
|
+
if (result = await RecentBacktest.getLatestSignal(symbol, context.strategyName, context.exchangeName, context.frameName, true)) {
|
|
46061
|
+
return result;
|
|
46062
|
+
}
|
|
46063
|
+
if (result = await RecentLive.getLatestSignal(symbol, context.strategyName, context.exchangeName, context.frameName, false)) {
|
|
46064
|
+
return result;
|
|
46065
|
+
}
|
|
46066
|
+
return null;
|
|
46067
|
+
};
|
|
46068
|
+
}
|
|
46069
|
+
}
|
|
46070
|
+
/**
|
|
46071
|
+
* Global singleton instance of RecentAdapter.
|
|
46072
|
+
* Provides unified recent signal management for backtest and live trading.
|
|
46073
|
+
*/
|
|
46074
|
+
const Recent = new RecentAdapter();
|
|
46075
|
+
/**
|
|
46076
|
+
* Global singleton instance of RecentLiveAdapter.
|
|
46077
|
+
* Provides live trading recent signal storage with pluggable backends.
|
|
46078
|
+
*/
|
|
46079
|
+
const RecentLive = new RecentLiveAdapter();
|
|
46080
|
+
/**
|
|
46081
|
+
* Global singleton instance of RecentBacktestAdapter.
|
|
46082
|
+
* Provides backtest recent signal storage with pluggable backends.
|
|
46083
|
+
*/
|
|
46084
|
+
const RecentBacktest = new RecentBacktestAdapter();
|
|
46085
|
+
|
|
46086
|
+
const GET_LATEST_SIGNAL_METHOD_NAME = "signal.getLatestSignal";
|
|
46087
|
+
/**
|
|
46088
|
+
* Returns the latest signal (pending or closed) for the current strategy context.
|
|
46089
|
+
*
|
|
46090
|
+
* Does not distinguish between active and closed signals — returns whichever
|
|
46091
|
+
* was recorded last. Useful for cooldown logic: e.g. skip opening a new position
|
|
46092
|
+
* for 4 hours after a stop-loss by checking the timestamp of the latest signal
|
|
46093
|
+
* regardless of its outcome.
|
|
46094
|
+
*
|
|
46095
|
+
* Searches backtest storage first, then live storage.
|
|
46096
|
+
* Returns null if no signal exists at all.
|
|
46097
|
+
*
|
|
46098
|
+
* Automatically detects backtest/live mode from execution context.
|
|
46099
|
+
*
|
|
46100
|
+
* @param symbol - Trading pair symbol
|
|
46101
|
+
* @returns Promise resolving to the latest signal or null
|
|
46102
|
+
*
|
|
46103
|
+
* @example
|
|
46104
|
+
* ```typescript
|
|
46105
|
+
* import { getLatestSignal } from "backtest-kit";
|
|
46106
|
+
*
|
|
46107
|
+
* const latest = await getLatestSignal("BTCUSDT");
|
|
46108
|
+
* if (latest && Date.now() - latest.closedAt < 4 * 60 * 60 * 1000) {
|
|
46109
|
+
* return; // cooldown after SL — skip new signal for 4 hours
|
|
46110
|
+
* }
|
|
46111
|
+
* ```
|
|
46112
|
+
*/
|
|
46113
|
+
async function getLatestSignal(symbol) {
|
|
46114
|
+
backtest.loggerService.info(GET_LATEST_SIGNAL_METHOD_NAME, { symbol });
|
|
46115
|
+
if (!ExecutionContextService.hasContext()) {
|
|
46116
|
+
throw new Error("getLatestSignal requires an execution context");
|
|
46117
|
+
}
|
|
46118
|
+
if (!MethodContextService.hasContext()) {
|
|
46119
|
+
throw new Error("getLatestSignal requires a method context");
|
|
46120
|
+
}
|
|
46121
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
46122
|
+
return await Recent.getLatestSignal(symbol, { exchangeName, frameName, strategyName });
|
|
46123
|
+
}
|
|
46124
|
+
|
|
45231
46125
|
const DEFAULT_BM25_K1 = 1.5;
|
|
45232
46126
|
const DEFAULT_BM25_B = 0.75;
|
|
45233
46127
|
const DEFAULT_BM25_SCORE = 0.5;
|
|
@@ -47756,6 +48650,87 @@ class MarkdownUtils {
|
|
|
47756
48650
|
backtest.maxDrawdownMarkdownService.unsubscribe();
|
|
47757
48651
|
}
|
|
47758
48652
|
};
|
|
48653
|
+
/**
|
|
48654
|
+
* Clears markdown report data selectively.
|
|
48655
|
+
*
|
|
48656
|
+
* Clears accumulated data for specified markdown services without unsubscribing.
|
|
48657
|
+
* Use this method to reset report data for specific services while keeping them active.
|
|
48658
|
+
*
|
|
48659
|
+
* Each cleared service will:
|
|
48660
|
+
* - Clear accumulated data for all reports
|
|
48661
|
+
* - Start fresh with new data for future events
|
|
48662
|
+
* - Not affect event subscriptions or report generation status
|
|
48663
|
+
*
|
|
48664
|
+
* @param config - Service configuration object specifying which services to clear. Defaults to clearing all services.
|
|
48665
|
+
* @param config.backtest - Clear backtest result report data
|
|
48666
|
+
* @param config.breakeven - Clear breakeven event tracking data
|
|
48667
|
+
* @param config.partial - Clear partial profit/loss event tracking data
|
|
48668
|
+
* @param config.heat - Clear portfolio heatmap analysis data
|
|
48669
|
+
* @param config.walker - Clear walker strategy comparison report data
|
|
48670
|
+
* @param config.performance - Clear performance bottleneck analysis data
|
|
48671
|
+
* @param config.risk - Clear risk rejection tracking data
|
|
48672
|
+
* @param config.schedule - Clear scheduled signal tracking data
|
|
48673
|
+
* @param config.live - Clear live trading event report data
|
|
48674
|
+
* @param config.strategy - Clear strategy report data
|
|
48675
|
+
* @param config.sync - Clear sync report data
|
|
48676
|
+
* @param config.highest_profit - Clear highest profit report data
|
|
48677
|
+
* @param config.max_drawdown - Clear max drawdown report data
|
|
48678
|
+
*/
|
|
48679
|
+
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) => {
|
|
48680
|
+
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_CLEAR, {
|
|
48681
|
+
backtest: bt,
|
|
48682
|
+
breakeven,
|
|
48683
|
+
heat,
|
|
48684
|
+
live,
|
|
48685
|
+
partial,
|
|
48686
|
+
performance,
|
|
48687
|
+
risk,
|
|
48688
|
+
strategy,
|
|
48689
|
+
schedule,
|
|
48690
|
+
walker,
|
|
48691
|
+
sync,
|
|
48692
|
+
highest_profit,
|
|
48693
|
+
});
|
|
48694
|
+
if (bt) {
|
|
48695
|
+
backtest.backtestMarkdownService.clear();
|
|
48696
|
+
}
|
|
48697
|
+
if (breakeven) {
|
|
48698
|
+
backtest.breakevenMarkdownService.clear();
|
|
48699
|
+
}
|
|
48700
|
+
if (heat) {
|
|
48701
|
+
backtest.heatMarkdownService.clear();
|
|
48702
|
+
}
|
|
48703
|
+
if (live) {
|
|
48704
|
+
backtest.liveMarkdownService.clear();
|
|
48705
|
+
}
|
|
48706
|
+
if (partial) {
|
|
48707
|
+
backtest.partialMarkdownService.clear();
|
|
48708
|
+
}
|
|
48709
|
+
if (performance) {
|
|
48710
|
+
backtest.performanceMarkdownService.clear();
|
|
48711
|
+
}
|
|
48712
|
+
if (risk) {
|
|
48713
|
+
backtest.riskMarkdownService.clear();
|
|
48714
|
+
}
|
|
48715
|
+
if (strategy) {
|
|
48716
|
+
backtest.strategyMarkdownService.clear();
|
|
48717
|
+
}
|
|
48718
|
+
if (schedule) {
|
|
48719
|
+
backtest.scheduleMarkdownService.clear();
|
|
48720
|
+
}
|
|
48721
|
+
if (walker) {
|
|
48722
|
+
backtest.walkerMarkdownService.clear();
|
|
48723
|
+
}
|
|
48724
|
+
if (sync) {
|
|
48725
|
+
backtest.syncMarkdownService.clear();
|
|
48726
|
+
}
|
|
48727
|
+
if (highest_profit) {
|
|
48728
|
+
backtest.highestProfitMarkdownService.clear();
|
|
48729
|
+
}
|
|
48730
|
+
if (max_drawdown) {
|
|
48731
|
+
backtest.maxDrawdownMarkdownService.clear();
|
|
48732
|
+
}
|
|
48733
|
+
};
|
|
47759
48734
|
}
|
|
47760
48735
|
}
|
|
47761
48736
|
/**
|
|
@@ -47798,15 +48773,6 @@ class MarkdownAdapter extends MarkdownUtils {
|
|
|
47798
48773
|
LOGGER_SERVICE$1.debug(MARKDOWN_METHOD_NAME_USE_JSONL);
|
|
47799
48774
|
MarkdownWriter.useJsonl();
|
|
47800
48775
|
}
|
|
47801
|
-
/**
|
|
47802
|
-
* Clears the memoized storage cache.
|
|
47803
|
-
* Call this when process.cwd() changes between strategy iterations
|
|
47804
|
-
* so new storage instances are created with the updated base path.
|
|
47805
|
-
*/
|
|
47806
|
-
clear() {
|
|
47807
|
-
LOGGER_SERVICE$1.log(MARKDOWN_METHOD_NAME_CLEAR);
|
|
47808
|
-
MarkdownWriter.clear();
|
|
47809
|
-
}
|
|
47810
48776
|
/**
|
|
47811
48777
|
* Switches to a dummy markdown adapter that discards all writes.
|
|
47812
48778
|
* All future markdown writes will be no-ops.
|
|
@@ -48478,6 +49444,68 @@ class LogAdapter {
|
|
|
48478
49444
|
*/
|
|
48479
49445
|
const Log = new LogAdapter();
|
|
48480
49446
|
|
|
49447
|
+
const METHOD_NAME_CREATE_SNAPSHOT = "SessionUtils.createSnapshot";
|
|
49448
|
+
/** List of all global subjects whose listeners should be snapshotted for session isolation */
|
|
49449
|
+
const SUBJECT_ISOLATION_LIST = [
|
|
49450
|
+
activePingSubject,
|
|
49451
|
+
backtestScheduleOpenSubject,
|
|
49452
|
+
breakevenSubject,
|
|
49453
|
+
doneBacktestSubject,
|
|
49454
|
+
doneLiveSubject,
|
|
49455
|
+
errorEmitter,
|
|
49456
|
+
exitEmitter,
|
|
49457
|
+
highestProfitSubject,
|
|
49458
|
+
maxDrawdownSubject,
|
|
49459
|
+
partialLossSubject,
|
|
49460
|
+
partialProfitSubject,
|
|
49461
|
+
performanceEmitter,
|
|
49462
|
+
progressBacktestEmitter,
|
|
49463
|
+
riskSubject,
|
|
49464
|
+
schedulePingSubject,
|
|
49465
|
+
shutdownEmitter,
|
|
49466
|
+
signalBacktestEmitter,
|
|
49467
|
+
signalEmitter,
|
|
49468
|
+
signalLiveEmitter,
|
|
49469
|
+
strategyCommitSubject,
|
|
49470
|
+
syncSubject,
|
|
49471
|
+
validationSubject,
|
|
49472
|
+
signalNotifySubject,
|
|
49473
|
+
];
|
|
49474
|
+
/**
|
|
49475
|
+
* Creates a snapshot function for a given subject by clearing its internal
|
|
49476
|
+
* events map and returning a restore function that can put the original listeners back.
|
|
49477
|
+
* @param subject The subject to snapshot
|
|
49478
|
+
* @returns A function that restores the subject's original listeners when called
|
|
49479
|
+
*/
|
|
49480
|
+
const CREATE_SUBJECT_SNAPSHOT_FN = (subject) => {
|
|
49481
|
+
const emitter = subject["_emitter"];
|
|
49482
|
+
const events = emitter["_events"];
|
|
49483
|
+
emitter["_events"] = {};
|
|
49484
|
+
return () => {
|
|
49485
|
+
emitter["_events"] = events;
|
|
49486
|
+
};
|
|
49487
|
+
};
|
|
49488
|
+
/**
|
|
49489
|
+
* Manages isolation of global event-bus state between backtest sessions.
|
|
49490
|
+
* Allows temporarily detaching all subject subscriptions so that one session
|
|
49491
|
+
* does not interfere with another, then restoring them afterwards.
|
|
49492
|
+
*/
|
|
49493
|
+
class SessionUtils {
|
|
49494
|
+
constructor() {
|
|
49495
|
+
/**
|
|
49496
|
+
* Snapshots the current listener state of every global subject by replacing
|
|
49497
|
+
* their internal `_events` map with an empty object.
|
|
49498
|
+
* @returns A restore function that, when called, puts all original listeners back.
|
|
49499
|
+
*/
|
|
49500
|
+
this.createSnapshot = () => {
|
|
49501
|
+
backtest.loggerService.log(METHOD_NAME_CREATE_SNAPSHOT);
|
|
49502
|
+
const snapshotList = SUBJECT_ISOLATION_LIST.map(CREATE_SUBJECT_SNAPSHOT_FN);
|
|
49503
|
+
return compose(...snapshotList);
|
|
49504
|
+
};
|
|
49505
|
+
}
|
|
49506
|
+
}
|
|
49507
|
+
const Session = new SessionUtils();
|
|
49508
|
+
|
|
48481
49509
|
const SCHEDULE_METHOD_NAME_GET_DATA = "ScheduleUtils.getData";
|
|
48482
49510
|
const SCHEDULE_METHOD_NAME_GET_REPORT = "ScheduleUtils.getReport";
|
|
48483
49511
|
const SCHEDULE_METHOD_NAME_DUMP = "ScheduleUtils.dump";
|
|
@@ -53287,7 +54315,44 @@ const CREATE_VALIDATION_ERROR_NOTIFICATION_FN = (error) => ({
|
|
|
53287
54315
|
message: getErrorMessage(error),
|
|
53288
54316
|
backtest: false,
|
|
53289
54317
|
});
|
|
54318
|
+
/**
|
|
54319
|
+
* Creates a notification model for signal info events.
|
|
54320
|
+
* @param data - The signal info contract data
|
|
54321
|
+
* @returns NotificationModel for signal info event
|
|
54322
|
+
*/
|
|
54323
|
+
const CREATE_SIGNAL_INFO_NOTIFICATION_FN = (data) => ({
|
|
54324
|
+
type: "signal.info",
|
|
54325
|
+
id: CREATE_KEY_FN$2(),
|
|
54326
|
+
timestamp: data.timestamp,
|
|
54327
|
+
backtest: data.backtest,
|
|
54328
|
+
symbol: data.symbol,
|
|
54329
|
+
strategyName: data.strategyName,
|
|
54330
|
+
exchangeName: data.exchangeName,
|
|
54331
|
+
signalId: data.data.id,
|
|
54332
|
+
currentPrice: data.currentPrice,
|
|
54333
|
+
position: data.data.position,
|
|
54334
|
+
priceOpen: data.data.priceOpen,
|
|
54335
|
+
priceTakeProfit: data.data.priceTakeProfit,
|
|
54336
|
+
priceStopLoss: data.data.priceStopLoss,
|
|
54337
|
+
originalPriceTakeProfit: data.data.originalPriceTakeProfit,
|
|
54338
|
+
originalPriceStopLoss: data.data.originalPriceStopLoss,
|
|
54339
|
+
originalPriceOpen: data.data.originalPriceOpen,
|
|
54340
|
+
totalEntries: data.data.totalEntries,
|
|
54341
|
+
totalPartials: data.data.totalPartials,
|
|
54342
|
+
pnl: data.data.pnl,
|
|
54343
|
+
pnlPercentage: data.data.pnl.pnlPercentage,
|
|
54344
|
+
pnlPriceOpen: data.data.pnl.priceOpen,
|
|
54345
|
+
pnlPriceClose: data.data.pnl.priceClose,
|
|
54346
|
+
pnlCost: data.data.pnl.pnlCost,
|
|
54347
|
+
pnlEntries: data.data.pnl.pnlEntries,
|
|
54348
|
+
note: data.note,
|
|
54349
|
+
notificationId: data.notificationId,
|
|
54350
|
+
scheduledAt: data.data.scheduledAt,
|
|
54351
|
+
pendingAt: data.data.pendingAt,
|
|
54352
|
+
createdAt: data.timestamp,
|
|
54353
|
+
});
|
|
53290
54354
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryBacktestUtils.handleSignal";
|
|
54355
|
+
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryBacktestUtils.handleSignalNotify";
|
|
53291
54356
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryBacktestUtils.handlePartialProfit";
|
|
53292
54357
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryBacktestUtils.handlePartialLoss";
|
|
53293
54358
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryBacktestUtils.handleBreakeven";
|
|
@@ -53300,6 +54365,7 @@ const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_VALIDATION_ERROR = "Notifi
|
|
|
53300
54365
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_GET_DATA = "NotificationMemoryBacktestUtils.getData";
|
|
53301
54366
|
const NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_DISPOSE = "NotificationMemoryBacktestUtils.dispose";
|
|
53302
54367
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationMemoryLiveUtils.handleSignal";
|
|
54368
|
+
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationMemoryLiveUtils.handleSignalNotify";
|
|
53303
54369
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationMemoryLiveUtils.handlePartialProfit";
|
|
53304
54370
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationMemoryLiveUtils.handlePartialLoss";
|
|
53305
54371
|
const NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationMemoryLiveUtils.handleBreakeven";
|
|
@@ -53328,6 +54394,7 @@ const NOTIFICATION_LIVE_ADAPTER_METHOD_NAME_CLEAR = "NotificationLiveAdapter.cle
|
|
|
53328
54394
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistBacktestUtils.waitForInit";
|
|
53329
54395
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistBacktestUtils._updateNotifications";
|
|
53330
54396
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistBacktestUtils.handleSignal";
|
|
54397
|
+
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistBacktestUtils.handleSignalNotify";
|
|
53331
54398
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistBacktestUtils.handlePartialProfit";
|
|
53332
54399
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistBacktestUtils.handlePartialLoss";
|
|
53333
54400
|
const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistBacktestUtils.handleBreakeven";
|
|
@@ -53342,6 +54409,7 @@ const NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_DISPOSE = "NotificationPersistBa
|
|
|
53342
54409
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_WAIT_FOR_INIT = "NotificationPersistLiveUtils.waitForInit";
|
|
53343
54410
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_UPDATE_NOTIFICATIONS = "NotificationPersistLiveUtils._updateNotifications";
|
|
53344
54411
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL = "NotificationPersistLiveUtils.handleSignal";
|
|
54412
|
+
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY = "NotificationPersistLiveUtils.handleSignalNotify";
|
|
53345
54413
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_PROFIT = "NotificationPersistLiveUtils.handlePartialProfit";
|
|
53346
54414
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_PARTIAL_LOSS = "NotificationPersistLiveUtils.handlePartialLoss";
|
|
53347
54415
|
const NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_BREAKEVEN = "NotificationPersistLiveUtils.handleBreakeven";
|
|
@@ -53384,6 +54452,12 @@ class NotificationMemoryBacktestUtils {
|
|
|
53384
54452
|
this._addNotification(notification);
|
|
53385
54453
|
}
|
|
53386
54454
|
};
|
|
54455
|
+
this.handleSignalNotify = async (data) => {
|
|
54456
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
54457
|
+
signalId: data.data.id,
|
|
54458
|
+
});
|
|
54459
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
54460
|
+
};
|
|
53387
54461
|
/**
|
|
53388
54462
|
* Handles partial profit availability event.
|
|
53389
54463
|
* @param data - The partial profit contract data
|
|
@@ -53528,6 +54602,8 @@ class NotificationDummyBacktestUtils {
|
|
|
53528
54602
|
*/
|
|
53529
54603
|
this.handleSignal = async () => {
|
|
53530
54604
|
};
|
|
54605
|
+
this.handleSignalNotify = async () => {
|
|
54606
|
+
};
|
|
53531
54607
|
/**
|
|
53532
54608
|
* No-op handler for partial profit event.
|
|
53533
54609
|
*/
|
|
@@ -53635,6 +54711,14 @@ class NotificationPersistBacktestUtils {
|
|
|
53635
54711
|
await this._updateNotifications();
|
|
53636
54712
|
}
|
|
53637
54713
|
};
|
|
54714
|
+
this.handleSignalNotify = async (data) => {
|
|
54715
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_BACKTEST_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
54716
|
+
signalId: data.data.id,
|
|
54717
|
+
});
|
|
54718
|
+
await this.waitForInit();
|
|
54719
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
54720
|
+
await this._updateNotifications();
|
|
54721
|
+
};
|
|
53638
54722
|
/**
|
|
53639
54723
|
* Handles partial profit availability event.
|
|
53640
54724
|
* @param data - The partial profit contract data
|
|
@@ -53836,6 +54920,12 @@ class NotificationMemoryLiveUtils {
|
|
|
53836
54920
|
this._addNotification(notification);
|
|
53837
54921
|
}
|
|
53838
54922
|
};
|
|
54923
|
+
this.handleSignalNotify = async (data) => {
|
|
54924
|
+
backtest.loggerService.info(NOTIFICATION_MEMORY_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
54925
|
+
signalId: data.data.id,
|
|
54926
|
+
});
|
|
54927
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
54928
|
+
};
|
|
53839
54929
|
/**
|
|
53840
54930
|
* Handles partial profit availability event.
|
|
53841
54931
|
* @param data - The partial profit contract data
|
|
@@ -53980,6 +55070,8 @@ class NotificationDummyLiveUtils {
|
|
|
53980
55070
|
*/
|
|
53981
55071
|
this.handleSignal = async () => {
|
|
53982
55072
|
};
|
|
55073
|
+
this.handleSignalNotify = async () => {
|
|
55074
|
+
};
|
|
53983
55075
|
/**
|
|
53984
55076
|
* No-op handler for partial profit event.
|
|
53985
55077
|
*/
|
|
@@ -54088,6 +55180,14 @@ class NotificationPersistLiveUtils {
|
|
|
54088
55180
|
await this._updateNotifications();
|
|
54089
55181
|
}
|
|
54090
55182
|
};
|
|
55183
|
+
this.handleSignalNotify = async (data) => {
|
|
55184
|
+
backtest.loggerService.info(NOTIFICATION_PERSIST_LIVE_METHOD_NAME_HANDLE_SIGNAL_NOTIFY, {
|
|
55185
|
+
signalId: data.data.id,
|
|
55186
|
+
});
|
|
55187
|
+
await this.waitForInit();
|
|
55188
|
+
this._addNotification(CREATE_SIGNAL_INFO_NOTIFICATION_FN(data));
|
|
55189
|
+
await this._updateNotifications();
|
|
55190
|
+
};
|
|
54091
55191
|
/**
|
|
54092
55192
|
* Handles partial profit availability event.
|
|
54093
55193
|
* @param data - The partial profit contract data
|
|
@@ -54281,6 +55381,9 @@ class NotificationBacktestAdapter {
|
|
|
54281
55381
|
this.handleSignal = async (data) => {
|
|
54282
55382
|
return await this._notificationBacktestUtils.handleSignal(data);
|
|
54283
55383
|
};
|
|
55384
|
+
this.handleSignalNotify = async (data) => {
|
|
55385
|
+
return await this._notificationBacktestUtils.handleSignalNotify(data);
|
|
55386
|
+
};
|
|
54284
55387
|
/**
|
|
54285
55388
|
* Handles partial profit availability event.
|
|
54286
55389
|
* Proxies call to the underlying notification adapter.
|
|
@@ -54436,6 +55539,9 @@ class NotificationLiveAdapter {
|
|
|
54436
55539
|
this.handleSignal = async (data) => {
|
|
54437
55540
|
return await this._notificationLiveUtils.handleSignal(data);
|
|
54438
55541
|
};
|
|
55542
|
+
this.handleSignalNotify = async (data) => {
|
|
55543
|
+
return await this._notificationLiveUtils.handleSignalNotify(data);
|
|
55544
|
+
};
|
|
54439
55545
|
/**
|
|
54440
55546
|
* Handles partial profit availability event.
|
|
54441
55547
|
* Proxies call to the underlying notification adapter.
|
|
@@ -54614,7 +55720,10 @@ class NotificationAdapter {
|
|
|
54614
55720
|
const unBacktestError = errorEmitter.subscribe((error) => NotificationBacktest.handleError(error));
|
|
54615
55721
|
const unBacktestExit = exitEmitter.subscribe((error) => NotificationBacktest.handleCriticalError(error));
|
|
54616
55722
|
const unBacktestValidation = validationSubject.subscribe((error) => NotificationBacktest.handleValidationError(error));
|
|
54617
|
-
|
|
55723
|
+
const unBacktestSignalNotify = signalNotifySubject
|
|
55724
|
+
.filter(({ backtest }) => backtest)
|
|
55725
|
+
.connect((data) => NotificationBacktest.handleSignalNotify(data));
|
|
55726
|
+
unBacktest = compose(() => unBacktestSignal(), () => unBacktestPartialProfit(), () => unBacktestPartialLoss(), () => unBacktestBreakeven(), () => unBacktestStrategyCommit(), () => unBacktestSync(), () => unBacktestRisk(), () => unBacktestError(), () => unBacktestExit(), () => unBacktestValidation(), () => unBacktestSignalNotify());
|
|
54618
55727
|
}
|
|
54619
55728
|
{
|
|
54620
55729
|
const unLiveSignal = signalLiveEmitter.subscribe((data) => NotificationLive.handleSignal(data));
|
|
@@ -54639,7 +55748,10 @@ class NotificationAdapter {
|
|
|
54639
55748
|
const unLiveError = errorEmitter.subscribe((error) => NotificationLive.handleError(error));
|
|
54640
55749
|
const unLiveExit = exitEmitter.subscribe((error) => NotificationLive.handleCriticalError(error));
|
|
54641
55750
|
const unLiveValidation = validationSubject.subscribe((error) => NotificationLive.handleValidationError(error));
|
|
54642
|
-
|
|
55751
|
+
const unLiveSignalNotify = signalNotifySubject
|
|
55752
|
+
.filter(({ backtest }) => !backtest)
|
|
55753
|
+
.connect((data) => NotificationLive.handleSignalNotify(data));
|
|
55754
|
+
unLive = compose(() => unLiveSignal(), () => unLivePartialProfit(), () => unLivePartialLoss(), () => unLiveBreakeven(), () => unLiveStrategyCommit(), () => unLiveSync(), () => unLiveRisk(), () => unLiveError(), () => unLiveExit(), () => unLiveValidation(), () => unLiveSignalNotify());
|
|
54643
55755
|
}
|
|
54644
55756
|
return () => {
|
|
54645
55757
|
unLive();
|
|
@@ -54715,12 +55827,15 @@ const CACHE_METHOD_NAME_RUN = "CacheFnInstance.run";
|
|
|
54715
55827
|
const CACHE_METHOD_NAME_FN = "CacheUtils.fn";
|
|
54716
55828
|
const CACHE_METHOD_NAME_FN_CLEAR = "CacheUtils.fn.clear";
|
|
54717
55829
|
const CACHE_METHOD_NAME_FN_GC = "CacheUtils.fn.gc";
|
|
55830
|
+
const CACHE_METHOD_NAME_FN_HAS_VALUE = "CacheUtils.fn.hasValue";
|
|
54718
55831
|
const CACHE_METHOD_NAME_FILE = "CacheUtils.file";
|
|
54719
55832
|
const CACHE_METHOD_NAME_FILE_CLEAR = "CacheUtils.file.clear";
|
|
55833
|
+
const CACHE_METHOD_NAME_FILE_HAS_VALUE = "CacheUtils.file.hasValue";
|
|
54720
55834
|
const CACHE_METHOD_NAME_DISPOSE = "CacheUtils.dispose";
|
|
54721
55835
|
const CACHE_METHOD_NAME_CLEAR = "CacheUtils.clear";
|
|
54722
55836
|
const CACHE_METHOD_NAME_RESET_COUNTER = "CacheUtils.resetCounter";
|
|
54723
55837
|
const CACHE_FILE_INSTANCE_METHOD_NAME_RUN = "CacheFileInstance.run";
|
|
55838
|
+
const CACHE_FILE_INSTANCE_METHOD_NAME_HAS_VALUE = "CacheFileInstance.hasValue";
|
|
54724
55839
|
const MS_PER_MINUTE$1 = 60000;
|
|
54725
55840
|
const INTERVAL_MINUTES$1 = {
|
|
54726
55841
|
"1m": 1,
|
|
@@ -54874,11 +55989,17 @@ class CacheFnInstance {
|
|
|
54874
55989
|
return cached;
|
|
54875
55990
|
}
|
|
54876
55991
|
}
|
|
55992
|
+
const value = this.fn(...args);
|
|
54877
55993
|
const newCache = {
|
|
54878
55994
|
when: currentWhen,
|
|
54879
|
-
value
|
|
55995
|
+
value,
|
|
54880
55996
|
};
|
|
54881
55997
|
this._cacheMap.set(key, newCache);
|
|
55998
|
+
if (value && value instanceof Promise) {
|
|
55999
|
+
value.catch(() => {
|
|
56000
|
+
this._cacheMap.delete(key);
|
|
56001
|
+
});
|
|
56002
|
+
}
|
|
54882
56003
|
return newCache;
|
|
54883
56004
|
};
|
|
54884
56005
|
/**
|
|
@@ -54910,6 +56031,36 @@ class CacheFnInstance {
|
|
|
54910
56031
|
}
|
|
54911
56032
|
}
|
|
54912
56033
|
};
|
|
56034
|
+
/**
|
|
56035
|
+
* Check whether a valid (non-expired) cache entry exists for the current context and arguments.
|
|
56036
|
+
*
|
|
56037
|
+
* Returns `true` if a cached value exists and its interval is still current.
|
|
56038
|
+
* Returns `false` if there is no entry or the cached entry has expired.
|
|
56039
|
+
*
|
|
56040
|
+
* Requires active execution context and method context.
|
|
56041
|
+
*
|
|
56042
|
+
* @param args - Arguments to look up in the cache
|
|
56043
|
+
* @returns `true` if a fresh cached value exists, `false` otherwise
|
|
56044
|
+
*/
|
|
56045
|
+
this.hasValue = (...args) => {
|
|
56046
|
+
if (!MethodContextService.hasContext()) {
|
|
56047
|
+
throw new Error("CacheFnInstance hasValue requires method context");
|
|
56048
|
+
}
|
|
56049
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56050
|
+
throw new Error("CacheFnInstance hasValue requires execution context");
|
|
56051
|
+
}
|
|
56052
|
+
const contextKey = CREATE_KEY_FN$1(backtest.methodContextService.context.strategyName, backtest.methodContextService.context.exchangeName, backtest.methodContextService.context.frameName, backtest.executionContextService.context.backtest);
|
|
56053
|
+
const argKey = String(this.key(args));
|
|
56054
|
+
const key = `${contextKey}:${argKey}`;
|
|
56055
|
+
const cached = this._cacheMap.get(key);
|
|
56056
|
+
if (!cached) {
|
|
56057
|
+
return false;
|
|
56058
|
+
}
|
|
56059
|
+
const currentWhen = backtest.executionContextService.context.when;
|
|
56060
|
+
const currentAligned = align$1(currentWhen.getTime(), this.interval);
|
|
56061
|
+
const cachedAligned = align$1(cached.when.getTime(), this.interval);
|
|
56062
|
+
return currentAligned === cachedAligned;
|
|
56063
|
+
};
|
|
54913
56064
|
/**
|
|
54914
56065
|
* Garbage collect expired cache entries.
|
|
54915
56066
|
*
|
|
@@ -55034,6 +56185,33 @@ class CacheFileInstance {
|
|
|
55034
56185
|
await PersistMeasureAdapter.writeMeasureData({ id: entityKey, data: result, removed: false }, bucket, entityKey);
|
|
55035
56186
|
return result;
|
|
55036
56187
|
};
|
|
56188
|
+
/**
|
|
56189
|
+
* Check whether a cached value exists on disk for the given arguments and current interval.
|
|
56190
|
+
*
|
|
56191
|
+
* Returns `true` if a persisted record exists for the current aligned timestamp.
|
|
56192
|
+
* Returns `false` if no record is found.
|
|
56193
|
+
*
|
|
56194
|
+
* Requires active execution context and method context.
|
|
56195
|
+
*
|
|
56196
|
+
* @param args - Arguments forwarded to the key generator
|
|
56197
|
+
* @returns `true` if a cached record exists, `false` otherwise
|
|
56198
|
+
*/
|
|
56199
|
+
this.hasValue = async (...args) => {
|
|
56200
|
+
backtest.loggerService.debug(CACHE_FILE_INSTANCE_METHOD_NAME_HAS_VALUE, { args });
|
|
56201
|
+
if (!MethodContextService.hasContext()) {
|
|
56202
|
+
throw new Error("CacheFileInstance hasValue requires method context");
|
|
56203
|
+
}
|
|
56204
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56205
|
+
throw new Error("CacheFileInstance hasValue requires execution context");
|
|
56206
|
+
}
|
|
56207
|
+
const [symbol, ...rest] = args;
|
|
56208
|
+
const { when } = backtest.executionContextService.context;
|
|
56209
|
+
const alignedTs = align$1(when.getTime(), this.interval);
|
|
56210
|
+
const bucket = `${this.name}_${this.interval}_${this.index}`;
|
|
56211
|
+
const entityKey = this.key([symbol, alignedTs, ...rest]);
|
|
56212
|
+
const cached = await PersistMeasureAdapter.readMeasureData(bucket, entityKey);
|
|
56213
|
+
return cached !== null;
|
|
56214
|
+
};
|
|
55037
56215
|
/**
|
|
55038
56216
|
* Soft-delete all persisted records for this instance's bucket.
|
|
55039
56217
|
* After this call the next `run()` will recompute and re-cache the value.
|
|
@@ -55120,23 +56298,30 @@ class CacheUtils {
|
|
|
55120
56298
|
wrappedFn.clear = () => {
|
|
55121
56299
|
backtest.loggerService.info(CACHE_METHOD_NAME_FN_CLEAR);
|
|
55122
56300
|
if (!MethodContextService.hasContext()) {
|
|
55123
|
-
|
|
55124
|
-
return;
|
|
56301
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_CLEAR} requires method context`);
|
|
55125
56302
|
}
|
|
55126
56303
|
if (!ExecutionContextService.hasContext()) {
|
|
55127
|
-
|
|
55128
|
-
return;
|
|
56304
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_CLEAR} requires execution context`);
|
|
55129
56305
|
}
|
|
55130
56306
|
this._getFnInstance.get(run)?.clear();
|
|
55131
56307
|
};
|
|
55132
56308
|
wrappedFn.gc = () => {
|
|
55133
56309
|
backtest.loggerService.info(CACHE_METHOD_NAME_FN_GC);
|
|
55134
56310
|
if (!ExecutionContextService.hasContext()) {
|
|
55135
|
-
|
|
55136
|
-
return;
|
|
56311
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_GC} requires execution context`);
|
|
55137
56312
|
}
|
|
55138
56313
|
return this._getFnInstance.get(run)?.gc();
|
|
55139
56314
|
};
|
|
56315
|
+
wrappedFn.hasValue = (...args) => {
|
|
56316
|
+
backtest.loggerService.info(CACHE_METHOD_NAME_FN_HAS_VALUE);
|
|
56317
|
+
if (!MethodContextService.hasContext()) {
|
|
56318
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_HAS_VALUE} requires method context`);
|
|
56319
|
+
}
|
|
56320
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56321
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_HAS_VALUE} requires execution context`);
|
|
56322
|
+
}
|
|
56323
|
+
return this._getFnInstance.get(run)?.hasValue(...args) ?? false;
|
|
56324
|
+
};
|
|
55140
56325
|
return wrappedFn;
|
|
55141
56326
|
};
|
|
55142
56327
|
/**
|
|
@@ -55188,8 +56373,25 @@ class CacheUtils {
|
|
|
55188
56373
|
};
|
|
55189
56374
|
wrappedFn.clear = async () => {
|
|
55190
56375
|
backtest.loggerService.info(CACHE_METHOD_NAME_FILE_CLEAR);
|
|
56376
|
+
if (!MethodContextService.hasContext()) {
|
|
56377
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_CLEAR} requires method context`);
|
|
56378
|
+
}
|
|
56379
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56380
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_CLEAR} requires execution context`);
|
|
56381
|
+
}
|
|
55191
56382
|
await this._getFileInstance.get(run)?.clear();
|
|
55192
56383
|
};
|
|
56384
|
+
wrappedFn.hasValue = async (...args) => {
|
|
56385
|
+
backtest.loggerService.info(CACHE_METHOD_NAME_FILE_HAS_VALUE);
|
|
56386
|
+
if (!MethodContextService.hasContext()) {
|
|
56387
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_HAS_VALUE} requires method context`);
|
|
56388
|
+
}
|
|
56389
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56390
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_HAS_VALUE} requires execution context`);
|
|
56391
|
+
}
|
|
56392
|
+
const instance = this._getFileInstance(run, context.interval, context.name, context.key);
|
|
56393
|
+
return await instance.hasValue(...args);
|
|
56394
|
+
};
|
|
55193
56395
|
return wrappedFn;
|
|
55194
56396
|
};
|
|
55195
56397
|
/**
|
|
@@ -55258,11 +56460,14 @@ const Cache = new CacheUtils();
|
|
|
55258
56460
|
|
|
55259
56461
|
const INTERVAL_METHOD_NAME_RUN = "IntervalFnInstance.run";
|
|
55260
56462
|
const INTERVAL_FILE_INSTANCE_METHOD_NAME_RUN = "IntervalFileInstance.run";
|
|
56463
|
+
const INTERVAL_FILE_INSTANCE_METHOD_NAME_HAS_VALUE = "IntervalFileInstance.hasValue";
|
|
55261
56464
|
const INTERVAL_METHOD_NAME_FN = "IntervalUtils.fn";
|
|
55262
56465
|
const INTERVAL_METHOD_NAME_FN_CLEAR = "IntervalUtils.fn.clear";
|
|
55263
56466
|
const INTERVAL_METHOD_NAME_FN_GC = "IntervalUtils.fn.gc";
|
|
56467
|
+
const INTERVAL_METHOD_NAME_FN_HAS_VALUE = "IntervalUtils.fn.hasValue";
|
|
55264
56468
|
const INTERVAL_METHOD_NAME_FILE = "IntervalUtils.file";
|
|
55265
56469
|
const INTERVAL_METHOD_NAME_FILE_CLEAR = "IntervalUtils.file.clear";
|
|
56470
|
+
const INTERVAL_METHOD_NAME_FILE_HAS_VALUE = "IntervalUtils.file.hasValue";
|
|
55266
56471
|
const INTERVAL_METHOD_NAME_DISPOSE = "IntervalUtils.dispose";
|
|
55267
56472
|
const INTERVAL_METHOD_NAME_CLEAR = "IntervalUtils.clear";
|
|
55268
56473
|
const INTERVAL_METHOD_NAME_RESET_COUNTER = "IntervalUtils.resetCounter";
|
|
@@ -55375,7 +56580,7 @@ class IntervalFnInstance {
|
|
|
55375
56580
|
* within the same interval or when `fn` itself returned `null`
|
|
55376
56581
|
* @throws Error if method context, execution context, or interval is missing
|
|
55377
56582
|
*/
|
|
55378
|
-
this.run =
|
|
56583
|
+
this.run = (...args) => {
|
|
55379
56584
|
backtest.loggerService.debug(INTERVAL_METHOD_NAME_RUN, { args });
|
|
55380
56585
|
const step = INTERVAL_MINUTES[this.interval];
|
|
55381
56586
|
{
|
|
@@ -55397,10 +56602,15 @@ class IntervalFnInstance {
|
|
|
55397
56602
|
if (this._stateMap.get(stateKey) === currentAligned) {
|
|
55398
56603
|
return null;
|
|
55399
56604
|
}
|
|
55400
|
-
const result =
|
|
56605
|
+
const result = this.fn.apply(null, args);
|
|
55401
56606
|
if (result !== null) {
|
|
55402
56607
|
this._stateMap.set(stateKey, currentAligned);
|
|
55403
56608
|
}
|
|
56609
|
+
if (result && result instanceof Promise) {
|
|
56610
|
+
result.catch(() => {
|
|
56611
|
+
this._stateMap.delete(stateKey);
|
|
56612
|
+
});
|
|
56613
|
+
}
|
|
55404
56614
|
return result;
|
|
55405
56615
|
};
|
|
55406
56616
|
/**
|
|
@@ -55420,6 +56630,31 @@ class IntervalFnInstance {
|
|
|
55420
56630
|
}
|
|
55421
56631
|
}
|
|
55422
56632
|
};
|
|
56633
|
+
/**
|
|
56634
|
+
* Check whether the function has already fired for the current interval and context.
|
|
56635
|
+
*
|
|
56636
|
+
* Returns `true` if the function fired (non-null result) within the current interval boundary.
|
|
56637
|
+
* Returns `false` if there is no recorded firing for this interval.
|
|
56638
|
+
*
|
|
56639
|
+
* Requires active method context and execution context.
|
|
56640
|
+
*
|
|
56641
|
+
* @param args - Arguments to look up in the state map
|
|
56642
|
+
* @returns `true` if the function has already fired this interval, `false` otherwise
|
|
56643
|
+
*/
|
|
56644
|
+
this.hasValue = (...args) => {
|
|
56645
|
+
if (!MethodContextService.hasContext()) {
|
|
56646
|
+
throw new Error("IntervalFnInstance hasValue requires method context");
|
|
56647
|
+
}
|
|
56648
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56649
|
+
throw new Error("IntervalFnInstance hasValue requires execution context");
|
|
56650
|
+
}
|
|
56651
|
+
const contextKey = CREATE_KEY_FN(backtest.methodContextService.context.strategyName, backtest.methodContextService.context.exchangeName, backtest.methodContextService.context.frameName, backtest.executionContextService.context.backtest);
|
|
56652
|
+
const currentWhen = backtest.executionContextService.context.when;
|
|
56653
|
+
const currentAligned = align(currentWhen.getTime(), this.interval);
|
|
56654
|
+
const argKey = this.key(args);
|
|
56655
|
+
const stateKey = `${contextKey}:${argKey}`;
|
|
56656
|
+
return this._stateMap.get(stateKey) === currentAligned;
|
|
56657
|
+
};
|
|
55423
56658
|
/**
|
|
55424
56659
|
* Garbage collect expired state entries.
|
|
55425
56660
|
*
|
|
@@ -55541,6 +56776,33 @@ class IntervalFileInstance {
|
|
|
55541
56776
|
}
|
|
55542
56777
|
return result;
|
|
55543
56778
|
};
|
|
56779
|
+
/**
|
|
56780
|
+
* Check whether the function has already fired for the current interval on disk.
|
|
56781
|
+
*
|
|
56782
|
+
* Returns `true` if a persisted record exists for the current aligned timestamp.
|
|
56783
|
+
* Returns `false` if no record is found.
|
|
56784
|
+
*
|
|
56785
|
+
* Requires active execution context and method context.
|
|
56786
|
+
*
|
|
56787
|
+
* @param args - Arguments forwarded to the key generator
|
|
56788
|
+
* @returns `true` if a fired record exists, `false` otherwise
|
|
56789
|
+
*/
|
|
56790
|
+
this.hasValue = async (...args) => {
|
|
56791
|
+
backtest.loggerService.debug(INTERVAL_FILE_INSTANCE_METHOD_NAME_HAS_VALUE, { args });
|
|
56792
|
+
if (!MethodContextService.hasContext()) {
|
|
56793
|
+
throw new Error("IntervalFileInstance hasValue requires method context");
|
|
56794
|
+
}
|
|
56795
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56796
|
+
throw new Error("IntervalFileInstance hasValue requires execution context");
|
|
56797
|
+
}
|
|
56798
|
+
const [symbol, ...rest] = args;
|
|
56799
|
+
const { when } = backtest.executionContextService.context;
|
|
56800
|
+
const alignedMs = align(when.getTime(), this.interval);
|
|
56801
|
+
const bucket = `${this.name}_${this.interval}_${this.index}`;
|
|
56802
|
+
const entityKey = this.key([symbol, alignedMs, ...rest]);
|
|
56803
|
+
const cached = await PersistIntervalAdapter.readIntervalData(bucket, entityKey);
|
|
56804
|
+
return cached !== null;
|
|
56805
|
+
};
|
|
55544
56806
|
/**
|
|
55545
56807
|
* Soft-delete all persisted records for this instance's bucket.
|
|
55546
56808
|
* After this call the function will fire again on the next `run()`.
|
|
@@ -55621,23 +56883,30 @@ class IntervalUtils {
|
|
|
55621
56883
|
wrappedFn.clear = () => {
|
|
55622
56884
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_CLEAR);
|
|
55623
56885
|
if (!MethodContextService.hasContext()) {
|
|
55624
|
-
|
|
55625
|
-
return;
|
|
56886
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_CLEAR} requires method context`);
|
|
55626
56887
|
}
|
|
55627
56888
|
if (!ExecutionContextService.hasContext()) {
|
|
55628
|
-
|
|
55629
|
-
return;
|
|
56889
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_CLEAR} requires execution context`);
|
|
55630
56890
|
}
|
|
55631
56891
|
this._getInstance.get(run)?.clear();
|
|
55632
56892
|
};
|
|
55633
56893
|
wrappedFn.gc = () => {
|
|
55634
56894
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_GC);
|
|
55635
56895
|
if (!ExecutionContextService.hasContext()) {
|
|
55636
|
-
|
|
55637
|
-
return;
|
|
56896
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_GC} requires execution context`);
|
|
55638
56897
|
}
|
|
55639
56898
|
return this._getInstance.get(run)?.gc();
|
|
55640
56899
|
};
|
|
56900
|
+
wrappedFn.hasValue = (...args) => {
|
|
56901
|
+
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_HAS_VALUE);
|
|
56902
|
+
if (!MethodContextService.hasContext()) {
|
|
56903
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_HAS_VALUE} requires method context`);
|
|
56904
|
+
}
|
|
56905
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56906
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_HAS_VALUE} requires execution context`);
|
|
56907
|
+
}
|
|
56908
|
+
return this._getInstance.get(run)?.hasValue(...args) ?? false;
|
|
56909
|
+
};
|
|
55641
56910
|
return wrappedFn;
|
|
55642
56911
|
};
|
|
55643
56912
|
/**
|
|
@@ -55680,8 +56949,25 @@ class IntervalUtils {
|
|
|
55680
56949
|
};
|
|
55681
56950
|
wrappedFn.clear = async () => {
|
|
55682
56951
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FILE_CLEAR);
|
|
56952
|
+
if (!MethodContextService.hasContext()) {
|
|
56953
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_CLEAR} requires method context`);
|
|
56954
|
+
}
|
|
56955
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56956
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_CLEAR} requires execution context`);
|
|
56957
|
+
}
|
|
55683
56958
|
await this._getFileInstance.get(run)?.clear();
|
|
55684
56959
|
};
|
|
56960
|
+
wrappedFn.hasValue = async (...args) => {
|
|
56961
|
+
backtest.loggerService.info(INTERVAL_METHOD_NAME_FILE_HAS_VALUE);
|
|
56962
|
+
if (!MethodContextService.hasContext()) {
|
|
56963
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_HAS_VALUE} requires method context`);
|
|
56964
|
+
}
|
|
56965
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56966
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_HAS_VALUE} requires execution context`);
|
|
56967
|
+
}
|
|
56968
|
+
const instance = this._getFileInstance(run, context.interval, context.name, context.key);
|
|
56969
|
+
return await instance.hasValue(...args);
|
|
56970
|
+
};
|
|
55685
56971
|
return wrappedFn;
|
|
55686
56972
|
};
|
|
55687
56973
|
/**
|
|
@@ -56855,4 +58141,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
56855
58141
|
return !errors.length;
|
|
56856
58142
|
};
|
|
56857
58143
|
|
|
56858
|
-
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, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PersistStorageAdapter, Position, PositionSize, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, 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, 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 };
|
|
58144
|
+
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, 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, 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 };
|