backtest-kit 6.12.0 → 6.13.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 +927 -85
- package/build/index.mjs +922 -86
- package/package.json +1 -1
- package/types.d.ts +302 -1
package/build/index.cjs
CHANGED
|
@@ -1002,6 +1002,12 @@ const PERSIST_MEMORY_UTILS_METHOD_NAME_LIST_DATA = "PersistMemoryUtils.listMemor
|
|
|
1002
1002
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_HAS_DATA = "PersistMemoryUtils.hasMemoryData";
|
|
1003
1003
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_CLEAR = "PersistMemoryUtils.clear";
|
|
1004
1004
|
const PERSIST_MEMORY_UTILS_METHOD_NAME_DISPOSE = "PersistMemoryUtils.dispose";
|
|
1005
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER = "PersistRecentUtils.usePersistRecentAdapter";
|
|
1006
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA = "PersistRecentUtils.readRecentData";
|
|
1007
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA = "PersistRecentUtils.writeRecentData";
|
|
1008
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON = "PersistRecentUtils.useJson";
|
|
1009
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY = "PersistRecentUtils.useDummy";
|
|
1010
|
+
const PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR = "PersistRecentUtils.clear";
|
|
1005
1011
|
const BASE_WAIT_FOR_INIT_FN_METHOD_NAME = "PersistBase.waitForInitFn";
|
|
1006
1012
|
const BASE_UNLINK_RETRY_COUNT = 5;
|
|
1007
1013
|
const BASE_UNLINK_RETRY_DELAY = 1000;
|
|
@@ -2848,6 +2854,115 @@ class PersistMemoryUtils {
|
|
|
2848
2854
|
* ```
|
|
2849
2855
|
*/
|
|
2850
2856
|
const PersistMemoryAdapter = new PersistMemoryUtils();
|
|
2857
|
+
/**
|
|
2858
|
+
* Utility class for managing recent signal persistence.
|
|
2859
|
+
*
|
|
2860
|
+
* Features:
|
|
2861
|
+
* - Memoized storage instances per (symbol, strategyName, exchangeName, frameName) context
|
|
2862
|
+
* - Custom adapter support
|
|
2863
|
+
* - Atomic read/write operations
|
|
2864
|
+
* - Crash-safe recent signal state management
|
|
2865
|
+
*
|
|
2866
|
+
* Used by RecentPersistBacktestUtils/RecentPersistLiveUtils for recent signal persistence.
|
|
2867
|
+
*/
|
|
2868
|
+
class PersistRecentUtils {
|
|
2869
|
+
constructor() {
|
|
2870
|
+
this.PersistRecentFactory = PersistBase;
|
|
2871
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":"), (symbol, strategyName, exchangeName, frameName, backtest) => Reflect.construct(this.PersistRecentFactory, [
|
|
2872
|
+
this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join("_"),
|
|
2873
|
+
`./dump/data/recent/`,
|
|
2874
|
+
]));
|
|
2875
|
+
/**
|
|
2876
|
+
* Reads the latest persisted recent signal for a given context.
|
|
2877
|
+
*
|
|
2878
|
+
* Returns null if no recent signal exists.
|
|
2879
|
+
*
|
|
2880
|
+
* @param symbol - Trading pair symbol
|
|
2881
|
+
* @param strategyName - Strategy identifier
|
|
2882
|
+
* @param exchangeName - Exchange identifier
|
|
2883
|
+
* @param frameName - Frame identifier
|
|
2884
|
+
* @returns Promise resolving to recent signal or null
|
|
2885
|
+
*/
|
|
2886
|
+
this.readRecentData = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
2887
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_READ_DATA);
|
|
2888
|
+
const key = this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":");
|
|
2889
|
+
const isInitial = !this.getStorage.has(key);
|
|
2890
|
+
const stateStorage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
2891
|
+
await stateStorage.waitForInit(isInitial);
|
|
2892
|
+
if (await stateStorage.hasValue(symbol)) {
|
|
2893
|
+
return await stateStorage.readValue(symbol);
|
|
2894
|
+
}
|
|
2895
|
+
return null;
|
|
2896
|
+
};
|
|
2897
|
+
/**
|
|
2898
|
+
* Writes the latest recent signal to disk with atomic file writes.
|
|
2899
|
+
*
|
|
2900
|
+
* Uses symbol as the entity ID within the per-context storage instance.
|
|
2901
|
+
* Uses atomic writes to prevent corruption on crashes.
|
|
2902
|
+
*
|
|
2903
|
+
* @param signalRow - Recent signal data to persist
|
|
2904
|
+
* @param symbol - Trading pair symbol
|
|
2905
|
+
* @param strategyName - Strategy identifier
|
|
2906
|
+
* @param exchangeName - Exchange identifier
|
|
2907
|
+
* @param frameName - Frame identifier
|
|
2908
|
+
* @returns Promise that resolves when write is complete
|
|
2909
|
+
*/
|
|
2910
|
+
this.writeRecentData = async (signalRow, symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
2911
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_WRITE_DATA);
|
|
2912
|
+
const key = this.createKeyParts(symbol, strategyName, exchangeName, frameName, backtest).join(":");
|
|
2913
|
+
const isInitial = !this.getStorage.has(key);
|
|
2914
|
+
const stateStorage = this.getStorage(symbol, strategyName, exchangeName, frameName, backtest);
|
|
2915
|
+
await stateStorage.waitForInit(isInitial);
|
|
2916
|
+
await stateStorage.writeValue(symbol, signalRow);
|
|
2917
|
+
};
|
|
2918
|
+
}
|
|
2919
|
+
createKeyParts(symbol, strategyName, exchangeName, frameName, backtest) {
|
|
2920
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
2921
|
+
if (frameName)
|
|
2922
|
+
parts.push(frameName);
|
|
2923
|
+
parts.push(backtest ? "backtest" : "live");
|
|
2924
|
+
return parts;
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Registers a custom persistence adapter.
|
|
2928
|
+
*
|
|
2929
|
+
* @param Ctor - Custom PersistBase constructor
|
|
2930
|
+
*/
|
|
2931
|
+
usePersistRecentAdapter(Ctor) {
|
|
2932
|
+
LOGGER_SERVICE$7.info(PERSIST_RECENT_UTILS_METHOD_NAME_USE_PERSIST_RECENT_ADAPTER);
|
|
2933
|
+
this.PersistRecentFactory = Ctor;
|
|
2934
|
+
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Clears the memoized storage cache.
|
|
2937
|
+
* Call this when process.cwd() changes between strategy iterations
|
|
2938
|
+
* so new storage instances are created with the updated base path.
|
|
2939
|
+
*/
|
|
2940
|
+
clear() {
|
|
2941
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_CLEAR);
|
|
2942
|
+
this.getStorage.clear();
|
|
2943
|
+
}
|
|
2944
|
+
/**
|
|
2945
|
+
* Switches to the default JSON persist adapter.
|
|
2946
|
+
* All future persistence writes will use JSON storage.
|
|
2947
|
+
*/
|
|
2948
|
+
useJson() {
|
|
2949
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_JSON);
|
|
2950
|
+
this.usePersistRecentAdapter(PersistBase);
|
|
2951
|
+
}
|
|
2952
|
+
/**
|
|
2953
|
+
* Switches to a dummy persist adapter that discards all writes.
|
|
2954
|
+
* All future persistence writes will be no-ops.
|
|
2955
|
+
*/
|
|
2956
|
+
useDummy() {
|
|
2957
|
+
LOGGER_SERVICE$7.log(PERSIST_RECENT_UTILS_METHOD_NAME_USE_DUMMY);
|
|
2958
|
+
this.usePersistRecentAdapter(PersistDummy);
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Global singleton instance of PersistRecentUtils.
|
|
2963
|
+
* Used by RecentPersistBacktestUtils/RecentPersistLiveUtils for recent signal persistence.
|
|
2964
|
+
*/
|
|
2965
|
+
const PersistRecentAdapter = new PersistRecentUtils();
|
|
2851
2966
|
|
|
2852
2967
|
var _a$2, _b$2;
|
|
2853
2968
|
const BUSY_DELAY = 100;
|
|
@@ -10175,7 +10290,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
10175
10290
|
* @param backtest - Whether running in backtest mode
|
|
10176
10291
|
* @returns Unique string key for memoization
|
|
10177
10292
|
*/
|
|
10178
|
-
const CREATE_KEY_FN$
|
|
10293
|
+
const CREATE_KEY_FN$u = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10179
10294
|
const parts = [symbol, strategyName, exchangeName];
|
|
10180
10295
|
if (frameName)
|
|
10181
10296
|
parts.push(frameName);
|
|
@@ -10442,7 +10557,7 @@ class StrategyConnectionService {
|
|
|
10442
10557
|
* @param backtest - Whether running in backtest mode
|
|
10443
10558
|
* @returns Configured ClientStrategy instance
|
|
10444
10559
|
*/
|
|
10445
|
-
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
10560
|
+
this.getStrategy = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$u(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
10446
10561
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
10447
10562
|
return new ClientStrategy({
|
|
10448
10563
|
symbol,
|
|
@@ -11363,7 +11478,7 @@ class StrategyConnectionService {
|
|
|
11363
11478
|
}
|
|
11364
11479
|
return;
|
|
11365
11480
|
}
|
|
11366
|
-
const key = CREATE_KEY_FN$
|
|
11481
|
+
const key = CREATE_KEY_FN$u(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
11367
11482
|
if (!this.getStrategy.has(key)) {
|
|
11368
11483
|
return;
|
|
11369
11484
|
}
|
|
@@ -12532,7 +12647,7 @@ class ClientRisk {
|
|
|
12532
12647
|
* @param backtest - Whether running in backtest mode
|
|
12533
12648
|
* @returns Unique string key for memoization
|
|
12534
12649
|
*/
|
|
12535
|
-
const CREATE_KEY_FN$
|
|
12650
|
+
const CREATE_KEY_FN$t = (riskName, exchangeName, frameName, backtest) => {
|
|
12536
12651
|
const parts = [riskName, exchangeName];
|
|
12537
12652
|
if (frameName)
|
|
12538
12653
|
parts.push(frameName);
|
|
@@ -12632,7 +12747,7 @@ class RiskConnectionService {
|
|
|
12632
12747
|
* @param backtest - True if backtest mode, false if live mode
|
|
12633
12748
|
* @returns Configured ClientRisk instance
|
|
12634
12749
|
*/
|
|
12635
|
-
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
12750
|
+
this.getRisk = functoolsKit.memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$t(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
12636
12751
|
const schema = this.riskSchemaService.get(riskName);
|
|
12637
12752
|
return new ClientRisk({
|
|
12638
12753
|
...schema,
|
|
@@ -12701,7 +12816,7 @@ class RiskConnectionService {
|
|
|
12701
12816
|
payload,
|
|
12702
12817
|
});
|
|
12703
12818
|
if (payload) {
|
|
12704
|
-
const key = CREATE_KEY_FN$
|
|
12819
|
+
const key = CREATE_KEY_FN$t(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
12705
12820
|
this.getRisk.clear(key);
|
|
12706
12821
|
}
|
|
12707
12822
|
else {
|
|
@@ -13745,7 +13860,7 @@ class ClientAction {
|
|
|
13745
13860
|
* @param backtest - Whether running in backtest mode
|
|
13746
13861
|
* @returns Unique string key for memoization
|
|
13747
13862
|
*/
|
|
13748
|
-
const CREATE_KEY_FN$
|
|
13863
|
+
const CREATE_KEY_FN$s = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13749
13864
|
const parts = [actionName, strategyName, exchangeName];
|
|
13750
13865
|
if (frameName)
|
|
13751
13866
|
parts.push(frameName);
|
|
@@ -13797,7 +13912,7 @@ class ActionConnectionService {
|
|
|
13797
13912
|
* @param backtest - True if backtest mode, false if live mode
|
|
13798
13913
|
* @returns Configured ClientAction instance
|
|
13799
13914
|
*/
|
|
13800
|
-
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
13915
|
+
this.getAction = functoolsKit.memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$s(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
13801
13916
|
const schema = this.actionSchemaService.get(actionName);
|
|
13802
13917
|
return new ClientAction({
|
|
13803
13918
|
...schema,
|
|
@@ -14008,7 +14123,7 @@ class ActionConnectionService {
|
|
|
14008
14123
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
14009
14124
|
return;
|
|
14010
14125
|
}
|
|
14011
|
-
const key = CREATE_KEY_FN$
|
|
14126
|
+
const key = CREATE_KEY_FN$s(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
14012
14127
|
if (!this.getAction.has(key)) {
|
|
14013
14128
|
return;
|
|
14014
14129
|
}
|
|
@@ -14026,7 +14141,7 @@ const METHOD_NAME_VALIDATE$2 = "exchangeCoreService validate";
|
|
|
14026
14141
|
* @param exchangeName - Exchange name
|
|
14027
14142
|
* @returns Unique string key for memoization
|
|
14028
14143
|
*/
|
|
14029
|
-
const CREATE_KEY_FN$
|
|
14144
|
+
const CREATE_KEY_FN$r = (exchangeName) => {
|
|
14030
14145
|
return exchangeName;
|
|
14031
14146
|
};
|
|
14032
14147
|
/**
|
|
@@ -14050,7 +14165,7 @@ class ExchangeCoreService {
|
|
|
14050
14165
|
* @param exchangeName - Name of the exchange to validate
|
|
14051
14166
|
* @returns Promise that resolves when validation is complete
|
|
14052
14167
|
*/
|
|
14053
|
-
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
14168
|
+
this.validate = functoolsKit.memoize(([exchangeName]) => CREATE_KEY_FN$r(exchangeName), async (exchangeName) => {
|
|
14054
14169
|
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
14055
14170
|
exchangeName,
|
|
14056
14171
|
});
|
|
@@ -14302,7 +14417,7 @@ const METHOD_NAME_VALIDATE$1 = "strategyCoreService validate";
|
|
|
14302
14417
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14303
14418
|
* @returns Unique string key for memoization
|
|
14304
14419
|
*/
|
|
14305
|
-
const CREATE_KEY_FN$
|
|
14420
|
+
const CREATE_KEY_FN$q = (context) => {
|
|
14306
14421
|
const parts = [context.strategyName, context.exchangeName];
|
|
14307
14422
|
if (context.frameName)
|
|
14308
14423
|
parts.push(context.frameName);
|
|
@@ -14334,7 +14449,7 @@ class StrategyCoreService {
|
|
|
14334
14449
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
14335
14450
|
* @returns Promise that resolves when validation is complete
|
|
14336
14451
|
*/
|
|
14337
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
14452
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$q(context), async (context) => {
|
|
14338
14453
|
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
14339
14454
|
context,
|
|
14340
14455
|
});
|
|
@@ -15672,7 +15787,7 @@ class SizingGlobalService {
|
|
|
15672
15787
|
* @param context - Context with riskName, exchangeName, frameName
|
|
15673
15788
|
* @returns Unique string key for memoization
|
|
15674
15789
|
*/
|
|
15675
|
-
const CREATE_KEY_FN$
|
|
15790
|
+
const CREATE_KEY_FN$p = (context) => {
|
|
15676
15791
|
const parts = [context.riskName, context.exchangeName];
|
|
15677
15792
|
if (context.frameName)
|
|
15678
15793
|
parts.push(context.frameName);
|
|
@@ -15698,7 +15813,7 @@ class RiskGlobalService {
|
|
|
15698
15813
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
15699
15814
|
* @returns Promise that resolves when validation is complete
|
|
15700
15815
|
*/
|
|
15701
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
15816
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$p(context), async (context) => {
|
|
15702
15817
|
this.loggerService.log("riskGlobalService validate", {
|
|
15703
15818
|
context,
|
|
15704
15819
|
});
|
|
@@ -15776,7 +15891,7 @@ const METHOD_NAME_VALIDATE = "actionCoreService validate";
|
|
|
15776
15891
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
15777
15892
|
* @returns Unique string key for memoization
|
|
15778
15893
|
*/
|
|
15779
|
-
const CREATE_KEY_FN$
|
|
15894
|
+
const CREATE_KEY_FN$o = (context) => {
|
|
15780
15895
|
const parts = [context.strategyName, context.exchangeName];
|
|
15781
15896
|
if (context.frameName)
|
|
15782
15897
|
parts.push(context.frameName);
|
|
@@ -15820,7 +15935,7 @@ class ActionCoreService {
|
|
|
15820
15935
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
15821
15936
|
* @returns Promise that resolves when all validations complete
|
|
15822
15937
|
*/
|
|
15823
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
15938
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$o(context), async (context) => {
|
|
15824
15939
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
15825
15940
|
context,
|
|
15826
15941
|
});
|
|
@@ -20863,7 +20978,7 @@ const ReportWriter = new ReportWriterAdapter();
|
|
|
20863
20978
|
* @param backtest - Whether running in backtest mode
|
|
20864
20979
|
* @returns Unique string key for memoization
|
|
20865
20980
|
*/
|
|
20866
|
-
const CREATE_KEY_FN$
|
|
20981
|
+
const CREATE_KEY_FN$n = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
20867
20982
|
const parts = [symbol, strategyName, exchangeName];
|
|
20868
20983
|
if (frameName)
|
|
20869
20984
|
parts.push(frameName);
|
|
@@ -21109,7 +21224,7 @@ class BacktestMarkdownService {
|
|
|
21109
21224
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21110
21225
|
* Each combination gets its own isolated storage instance.
|
|
21111
21226
|
*/
|
|
21112
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21227
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$n(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$a(symbol, strategyName, exchangeName, frameName));
|
|
21113
21228
|
/**
|
|
21114
21229
|
* Processes tick events and accumulates closed signals.
|
|
21115
21230
|
* Should be called from IStrategyCallbacks.onTick.
|
|
@@ -21266,7 +21381,7 @@ class BacktestMarkdownService {
|
|
|
21266
21381
|
payload,
|
|
21267
21382
|
});
|
|
21268
21383
|
if (payload) {
|
|
21269
|
-
const key = CREATE_KEY_FN$
|
|
21384
|
+
const key = CREATE_KEY_FN$n(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
21270
21385
|
this.getStorage.clear(key);
|
|
21271
21386
|
}
|
|
21272
21387
|
else {
|
|
@@ -21328,7 +21443,7 @@ class BacktestMarkdownService {
|
|
|
21328
21443
|
* @param backtest - Whether running in backtest mode
|
|
21329
21444
|
* @returns Unique string key for memoization
|
|
21330
21445
|
*/
|
|
21331
|
-
const CREATE_KEY_FN$
|
|
21446
|
+
const CREATE_KEY_FN$m = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
21332
21447
|
const parts = [symbol, strategyName, exchangeName];
|
|
21333
21448
|
if (frameName)
|
|
21334
21449
|
parts.push(frameName);
|
|
@@ -21823,7 +21938,7 @@ class LiveMarkdownService {
|
|
|
21823
21938
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
21824
21939
|
* Each combination gets its own isolated storage instance.
|
|
21825
21940
|
*/
|
|
21826
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
21941
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$m(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$9(symbol, strategyName, exchangeName, frameName));
|
|
21827
21942
|
/**
|
|
21828
21943
|
* Subscribes to live signal emitter to receive tick events.
|
|
21829
21944
|
* Protected against multiple subscriptions.
|
|
@@ -22041,7 +22156,7 @@ class LiveMarkdownService {
|
|
|
22041
22156
|
payload,
|
|
22042
22157
|
});
|
|
22043
22158
|
if (payload) {
|
|
22044
|
-
const key = CREATE_KEY_FN$
|
|
22159
|
+
const key = CREATE_KEY_FN$m(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22045
22160
|
this.getStorage.clear(key);
|
|
22046
22161
|
}
|
|
22047
22162
|
else {
|
|
@@ -22061,7 +22176,7 @@ class LiveMarkdownService {
|
|
|
22061
22176
|
* @param backtest - Whether running in backtest mode
|
|
22062
22177
|
* @returns Unique string key for memoization
|
|
22063
22178
|
*/
|
|
22064
|
-
const CREATE_KEY_FN$
|
|
22179
|
+
const CREATE_KEY_FN$l = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22065
22180
|
const parts = [symbol, strategyName, exchangeName];
|
|
22066
22181
|
if (frameName)
|
|
22067
22182
|
parts.push(frameName);
|
|
@@ -22350,7 +22465,7 @@ class ScheduleMarkdownService {
|
|
|
22350
22465
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22351
22466
|
* Each combination gets its own isolated storage instance.
|
|
22352
22467
|
*/
|
|
22353
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22468
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$l(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$8(symbol, strategyName, exchangeName, frameName));
|
|
22354
22469
|
/**
|
|
22355
22470
|
* Subscribes to signal emitter to receive scheduled signal events.
|
|
22356
22471
|
* Protected against multiple subscriptions.
|
|
@@ -22553,7 +22668,7 @@ class ScheduleMarkdownService {
|
|
|
22553
22668
|
payload,
|
|
22554
22669
|
});
|
|
22555
22670
|
if (payload) {
|
|
22556
|
-
const key = CREATE_KEY_FN$
|
|
22671
|
+
const key = CREATE_KEY_FN$l(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22557
22672
|
this.getStorage.clear(key);
|
|
22558
22673
|
}
|
|
22559
22674
|
else {
|
|
@@ -22573,7 +22688,7 @@ class ScheduleMarkdownService {
|
|
|
22573
22688
|
* @param backtest - Whether running in backtest mode
|
|
22574
22689
|
* @returns Unique string key for memoization
|
|
22575
22690
|
*/
|
|
22576
|
-
const CREATE_KEY_FN$
|
|
22691
|
+
const CREATE_KEY_FN$k = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
22577
22692
|
const parts = [symbol, strategyName, exchangeName];
|
|
22578
22693
|
if (frameName)
|
|
22579
22694
|
parts.push(frameName);
|
|
@@ -22818,7 +22933,7 @@ class PerformanceMarkdownService {
|
|
|
22818
22933
|
* Memoized function to get or create PerformanceStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
22819
22934
|
* Each combination gets its own isolated storage instance.
|
|
22820
22935
|
*/
|
|
22821
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
22936
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$k(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new PerformanceStorage(symbol, strategyName, exchangeName, frameName));
|
|
22822
22937
|
/**
|
|
22823
22938
|
* Subscribes to performance emitter to receive performance events.
|
|
22824
22939
|
* Protected against multiple subscriptions.
|
|
@@ -22985,7 +23100,7 @@ class PerformanceMarkdownService {
|
|
|
22985
23100
|
payload,
|
|
22986
23101
|
});
|
|
22987
23102
|
if (payload) {
|
|
22988
|
-
const key = CREATE_KEY_FN$
|
|
23103
|
+
const key = CREATE_KEY_FN$k(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
22989
23104
|
this.getStorage.clear(key);
|
|
22990
23105
|
}
|
|
22991
23106
|
else {
|
|
@@ -23464,7 +23579,7 @@ class WalkerMarkdownService {
|
|
|
23464
23579
|
* @param backtest - Whether running in backtest mode
|
|
23465
23580
|
* @returns Unique string key for memoization
|
|
23466
23581
|
*/
|
|
23467
|
-
const CREATE_KEY_FN$
|
|
23582
|
+
const CREATE_KEY_FN$j = (exchangeName, frameName, backtest) => {
|
|
23468
23583
|
const parts = [exchangeName];
|
|
23469
23584
|
if (frameName)
|
|
23470
23585
|
parts.push(frameName);
|
|
@@ -23911,7 +24026,7 @@ class HeatMarkdownService {
|
|
|
23911
24026
|
* Memoized function to get or create HeatmapStorage for exchange, frame and backtest mode.
|
|
23912
24027
|
* Each exchangeName + frameName + backtest mode combination gets its own isolated heatmap storage instance.
|
|
23913
24028
|
*/
|
|
23914
|
-
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
24029
|
+
this.getStorage = functoolsKit.memoize(([exchangeName, frameName, backtest]) => CREATE_KEY_FN$j(exchangeName, frameName, backtest), (exchangeName, frameName, backtest) => new HeatmapStorage(exchangeName, frameName, backtest));
|
|
23915
24030
|
/**
|
|
23916
24031
|
* Subscribes to signal emitter to receive tick events.
|
|
23917
24032
|
* Protected against multiple subscriptions.
|
|
@@ -24129,7 +24244,7 @@ class HeatMarkdownService {
|
|
|
24129
24244
|
payload,
|
|
24130
24245
|
});
|
|
24131
24246
|
if (payload) {
|
|
24132
|
-
const key = CREATE_KEY_FN$
|
|
24247
|
+
const key = CREATE_KEY_FN$j(payload.exchangeName, payload.frameName, payload.backtest);
|
|
24133
24248
|
this.getStorage.clear(key);
|
|
24134
24249
|
}
|
|
24135
24250
|
else {
|
|
@@ -25160,7 +25275,7 @@ class ClientPartial {
|
|
|
25160
25275
|
* @param backtest - Whether running in backtest mode
|
|
25161
25276
|
* @returns Unique string key for memoization
|
|
25162
25277
|
*/
|
|
25163
|
-
const CREATE_KEY_FN$
|
|
25278
|
+
const CREATE_KEY_FN$i = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
25164
25279
|
/**
|
|
25165
25280
|
* Creates a callback function for emitting profit events to partialProfitSubject.
|
|
25166
25281
|
*
|
|
@@ -25282,7 +25397,7 @@ class PartialConnectionService {
|
|
|
25282
25397
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
25283
25398
|
* Value: ClientPartial instance with logger and event emitters
|
|
25284
25399
|
*/
|
|
25285
|
-
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
25400
|
+
this.getPartial = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$i(signalId, backtest), (signalId, backtest) => {
|
|
25286
25401
|
return new ClientPartial({
|
|
25287
25402
|
signalId,
|
|
25288
25403
|
logger: this.loggerService,
|
|
@@ -25372,7 +25487,7 @@ class PartialConnectionService {
|
|
|
25372
25487
|
const partial = this.getPartial(data.id, backtest);
|
|
25373
25488
|
await partial.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
25374
25489
|
await partial.clear(symbol, data, priceClose, backtest);
|
|
25375
|
-
const key = CREATE_KEY_FN$
|
|
25490
|
+
const key = CREATE_KEY_FN$i(data.id, backtest);
|
|
25376
25491
|
this.getPartial.clear(key);
|
|
25377
25492
|
};
|
|
25378
25493
|
}
|
|
@@ -25388,7 +25503,7 @@ class PartialConnectionService {
|
|
|
25388
25503
|
* @param backtest - Whether running in backtest mode
|
|
25389
25504
|
* @returns Unique string key for memoization
|
|
25390
25505
|
*/
|
|
25391
|
-
const CREATE_KEY_FN$
|
|
25506
|
+
const CREATE_KEY_FN$h = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
25392
25507
|
const parts = [symbol, strategyName, exchangeName];
|
|
25393
25508
|
if (frameName)
|
|
25394
25509
|
parts.push(frameName);
|
|
@@ -25611,7 +25726,7 @@ class PartialMarkdownService {
|
|
|
25611
25726
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
25612
25727
|
* Each combination gets its own isolated storage instance.
|
|
25613
25728
|
*/
|
|
25614
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
25729
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$h(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$6(symbol, strategyName, exchangeName, frameName));
|
|
25615
25730
|
/**
|
|
25616
25731
|
* Subscribes to partial profit/loss signal emitters to receive events.
|
|
25617
25732
|
* Protected against multiple subscriptions.
|
|
@@ -25821,7 +25936,7 @@ class PartialMarkdownService {
|
|
|
25821
25936
|
payload,
|
|
25822
25937
|
});
|
|
25823
25938
|
if (payload) {
|
|
25824
|
-
const key = CREATE_KEY_FN$
|
|
25939
|
+
const key = CREATE_KEY_FN$h(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
25825
25940
|
this.getStorage.clear(key);
|
|
25826
25941
|
}
|
|
25827
25942
|
else {
|
|
@@ -25837,7 +25952,7 @@ class PartialMarkdownService {
|
|
|
25837
25952
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
25838
25953
|
* @returns Unique string key for memoization
|
|
25839
25954
|
*/
|
|
25840
|
-
const CREATE_KEY_FN$
|
|
25955
|
+
const CREATE_KEY_FN$g = (context) => {
|
|
25841
25956
|
const parts = [context.strategyName, context.exchangeName];
|
|
25842
25957
|
if (context.frameName)
|
|
25843
25958
|
parts.push(context.frameName);
|
|
@@ -25911,7 +26026,7 @@ class PartialGlobalService {
|
|
|
25911
26026
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
25912
26027
|
* @param methodName - Name of the calling method for error tracking
|
|
25913
26028
|
*/
|
|
25914
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
26029
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$g(context), (context, methodName) => {
|
|
25915
26030
|
this.loggerService.log("partialGlobalService validate", {
|
|
25916
26031
|
context,
|
|
25917
26032
|
methodName,
|
|
@@ -26366,7 +26481,7 @@ class ClientBreakeven {
|
|
|
26366
26481
|
* @param backtest - Whether running in backtest mode
|
|
26367
26482
|
* @returns Unique string key for memoization
|
|
26368
26483
|
*/
|
|
26369
|
-
const CREATE_KEY_FN$
|
|
26484
|
+
const CREATE_KEY_FN$f = (signalId, backtest) => `${signalId}:${backtest ? "backtest" : "live"}`;
|
|
26370
26485
|
/**
|
|
26371
26486
|
* Creates a callback function for emitting breakeven events to breakevenSubject.
|
|
26372
26487
|
*
|
|
@@ -26452,7 +26567,7 @@ class BreakevenConnectionService {
|
|
|
26452
26567
|
* Key format: "signalId:backtest" or "signalId:live"
|
|
26453
26568
|
* Value: ClientBreakeven instance with logger and event emitter
|
|
26454
26569
|
*/
|
|
26455
|
-
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$
|
|
26570
|
+
this.getBreakeven = functoolsKit.memoize(([signalId, backtest]) => CREATE_KEY_FN$f(signalId, backtest), (signalId, backtest) => {
|
|
26456
26571
|
return new ClientBreakeven({
|
|
26457
26572
|
signalId,
|
|
26458
26573
|
logger: this.loggerService,
|
|
@@ -26513,7 +26628,7 @@ class BreakevenConnectionService {
|
|
|
26513
26628
|
const breakeven = this.getBreakeven(data.id, backtest);
|
|
26514
26629
|
await breakeven.waitForInit(symbol, data.strategyName, data.exchangeName, backtest);
|
|
26515
26630
|
await breakeven.clear(symbol, data, priceClose, backtest);
|
|
26516
|
-
const key = CREATE_KEY_FN$
|
|
26631
|
+
const key = CREATE_KEY_FN$f(data.id, backtest);
|
|
26517
26632
|
this.getBreakeven.clear(key);
|
|
26518
26633
|
};
|
|
26519
26634
|
}
|
|
@@ -26529,7 +26644,7 @@ class BreakevenConnectionService {
|
|
|
26529
26644
|
* @param backtest - Whether running in backtest mode
|
|
26530
26645
|
* @returns Unique string key for memoization
|
|
26531
26646
|
*/
|
|
26532
|
-
const CREATE_KEY_FN$
|
|
26647
|
+
const CREATE_KEY_FN$e = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
26533
26648
|
const parts = [symbol, strategyName, exchangeName];
|
|
26534
26649
|
if (frameName)
|
|
26535
26650
|
parts.push(frameName);
|
|
@@ -26704,7 +26819,7 @@ class BreakevenMarkdownService {
|
|
|
26704
26819
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
26705
26820
|
* Each combination gets its own isolated storage instance.
|
|
26706
26821
|
*/
|
|
26707
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
26822
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$e(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$5(symbol, strategyName, exchangeName, frameName));
|
|
26708
26823
|
/**
|
|
26709
26824
|
* Subscribes to breakeven signal emitter to receive events.
|
|
26710
26825
|
* Protected against multiple subscriptions.
|
|
@@ -26893,7 +27008,7 @@ class BreakevenMarkdownService {
|
|
|
26893
27008
|
payload,
|
|
26894
27009
|
});
|
|
26895
27010
|
if (payload) {
|
|
26896
|
-
const key = CREATE_KEY_FN$
|
|
27011
|
+
const key = CREATE_KEY_FN$e(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
26897
27012
|
this.getStorage.clear(key);
|
|
26898
27013
|
}
|
|
26899
27014
|
else {
|
|
@@ -26909,7 +27024,7 @@ class BreakevenMarkdownService {
|
|
|
26909
27024
|
* @param context - Context with strategyName, exchangeName, frameName
|
|
26910
27025
|
* @returns Unique string key for memoization
|
|
26911
27026
|
*/
|
|
26912
|
-
const CREATE_KEY_FN$
|
|
27027
|
+
const CREATE_KEY_FN$d = (context) => {
|
|
26913
27028
|
const parts = [context.strategyName, context.exchangeName];
|
|
26914
27029
|
if (context.frameName)
|
|
26915
27030
|
parts.push(context.frameName);
|
|
@@ -26983,7 +27098,7 @@ class BreakevenGlobalService {
|
|
|
26983
27098
|
* @param context - Context with strategyName, exchangeName and frameName
|
|
26984
27099
|
* @param methodName - Name of the calling method for error tracking
|
|
26985
27100
|
*/
|
|
26986
|
-
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$
|
|
27101
|
+
this.validate = functoolsKit.memoize(([context]) => CREATE_KEY_FN$d(context), (context, methodName) => {
|
|
26987
27102
|
this.loggerService.log("breakevenGlobalService validate", {
|
|
26988
27103
|
context,
|
|
26989
27104
|
methodName,
|
|
@@ -27204,7 +27319,7 @@ class ConfigValidationService {
|
|
|
27204
27319
|
* @param backtest - Whether running in backtest mode
|
|
27205
27320
|
* @returns Unique string key for memoization
|
|
27206
27321
|
*/
|
|
27207
|
-
const CREATE_KEY_FN$
|
|
27322
|
+
const CREATE_KEY_FN$c = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
27208
27323
|
const parts = [symbol, strategyName, exchangeName];
|
|
27209
27324
|
if (frameName)
|
|
27210
27325
|
parts.push(frameName);
|
|
@@ -27371,7 +27486,7 @@ class RiskMarkdownService {
|
|
|
27371
27486
|
* Memoized function to get or create ReportStorage for a symbol-strategy-exchange-frame-backtest combination.
|
|
27372
27487
|
* Each combination gets its own isolated storage instance.
|
|
27373
27488
|
*/
|
|
27374
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
27489
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$c(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$4(symbol, strategyName, exchangeName, frameName));
|
|
27375
27490
|
/**
|
|
27376
27491
|
* Subscribes to risk rejection emitter to receive rejection events.
|
|
27377
27492
|
* Protected against multiple subscriptions.
|
|
@@ -27560,7 +27675,7 @@ class RiskMarkdownService {
|
|
|
27560
27675
|
payload,
|
|
27561
27676
|
});
|
|
27562
27677
|
if (payload) {
|
|
27563
|
-
const key = CREATE_KEY_FN$
|
|
27678
|
+
const key = CREATE_KEY_FN$c(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
27564
27679
|
this.getStorage.clear(key);
|
|
27565
27680
|
}
|
|
27566
27681
|
else {
|
|
@@ -29942,7 +30057,7 @@ class HighestProfitReportService {
|
|
|
29942
30057
|
* @returns Colon-separated key string for memoization
|
|
29943
30058
|
* @internal
|
|
29944
30059
|
*/
|
|
29945
|
-
const CREATE_KEY_FN$
|
|
30060
|
+
const CREATE_KEY_FN$b = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
29946
30061
|
const parts = [symbol, strategyName, exchangeName];
|
|
29947
30062
|
if (frameName)
|
|
29948
30063
|
parts.push(frameName);
|
|
@@ -30184,7 +30299,7 @@ class StrategyMarkdownService {
|
|
|
30184
30299
|
*
|
|
30185
30300
|
* @internal
|
|
30186
30301
|
*/
|
|
30187
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
30302
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$3(symbol, strategyName, exchangeName, frameName));
|
|
30188
30303
|
/**
|
|
30189
30304
|
* Records a cancel-scheduled event when a scheduled signal is cancelled.
|
|
30190
30305
|
*
|
|
@@ -30758,7 +30873,7 @@ class StrategyMarkdownService {
|
|
|
30758
30873
|
this.clear = async (payload) => {
|
|
30759
30874
|
this.loggerService.log("strategyMarkdownService clear", { payload });
|
|
30760
30875
|
if (payload) {
|
|
30761
|
-
const key = CREATE_KEY_FN$
|
|
30876
|
+
const key = CREATE_KEY_FN$b(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
30762
30877
|
this.getStorage.clear(key);
|
|
30763
30878
|
}
|
|
30764
30879
|
else {
|
|
@@ -30866,7 +30981,7 @@ class StrategyMarkdownService {
|
|
|
30866
30981
|
* Creates a unique key for memoizing ReportStorage instances.
|
|
30867
30982
|
* Key format: "symbol:strategyName:exchangeName[:frameName]:backtest|live"
|
|
30868
30983
|
*/
|
|
30869
|
-
const CREATE_KEY_FN$
|
|
30984
|
+
const CREATE_KEY_FN$a = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
30870
30985
|
const parts = [symbol, strategyName, exchangeName];
|
|
30871
30986
|
if (frameName)
|
|
30872
30987
|
parts.push(frameName);
|
|
@@ -31059,7 +31174,7 @@ let ReportStorage$2 = class ReportStorage {
|
|
|
31059
31174
|
class SyncMarkdownService {
|
|
31060
31175
|
constructor() {
|
|
31061
31176
|
this.loggerService = inject(TYPES.loggerService);
|
|
31062
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31177
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$a(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => new ReportStorage$2(symbol, strategyName, exchangeName, frameName, backtest));
|
|
31063
31178
|
/**
|
|
31064
31179
|
* Subscribes to `syncSubject` to start receiving `SignalSyncContract` events.
|
|
31065
31180
|
* Protected against multiple subscriptions via `singleshot` — subsequent calls
|
|
@@ -31255,7 +31370,7 @@ class SyncMarkdownService {
|
|
|
31255
31370
|
this.clear = async (payload) => {
|
|
31256
31371
|
this.loggerService.log("syncMarkdownService clear", { payload });
|
|
31257
31372
|
if (payload) {
|
|
31258
|
-
const key = CREATE_KEY_FN$
|
|
31373
|
+
const key = CREATE_KEY_FN$a(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31259
31374
|
this.getStorage.clear(key);
|
|
31260
31375
|
}
|
|
31261
31376
|
else {
|
|
@@ -31268,7 +31383,7 @@ class SyncMarkdownService {
|
|
|
31268
31383
|
/**
|
|
31269
31384
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31270
31385
|
*/
|
|
31271
|
-
const CREATE_KEY_FN$
|
|
31386
|
+
const CREATE_KEY_FN$9 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31272
31387
|
const parts = [symbol, strategyName, exchangeName];
|
|
31273
31388
|
if (frameName)
|
|
31274
31389
|
parts.push(frameName);
|
|
@@ -31444,7 +31559,7 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
31444
31559
|
class HighestProfitMarkdownService {
|
|
31445
31560
|
constructor() {
|
|
31446
31561
|
this.loggerService = inject(TYPES.loggerService);
|
|
31447
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31562
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$9(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage$1(symbol, strategyName, exchangeName, frameName));
|
|
31448
31563
|
/**
|
|
31449
31564
|
* Subscribes to `highestProfitSubject` to start receiving `HighestProfitContract`
|
|
31450
31565
|
* events. Protected against multiple subscriptions via `singleshot` — subsequent
|
|
@@ -31610,7 +31725,7 @@ class HighestProfitMarkdownService {
|
|
|
31610
31725
|
this.clear = async (payload) => {
|
|
31611
31726
|
this.loggerService.log("highestProfitMarkdownService clear", { payload });
|
|
31612
31727
|
if (payload) {
|
|
31613
|
-
const key = CREATE_KEY_FN$
|
|
31728
|
+
const key = CREATE_KEY_FN$9(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31614
31729
|
this.getStorage.clear(key);
|
|
31615
31730
|
}
|
|
31616
31731
|
else {
|
|
@@ -31632,7 +31747,7 @@ const LISTEN_TIMEOUT$1 = 120000;
|
|
|
31632
31747
|
* @param backtest - Whether running in backtest mode
|
|
31633
31748
|
* @returns Unique string key for memoization
|
|
31634
31749
|
*/
|
|
31635
|
-
const CREATE_KEY_FN$
|
|
31750
|
+
const CREATE_KEY_FN$8 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31636
31751
|
const parts = [symbol, strategyName, exchangeName];
|
|
31637
31752
|
if (frameName)
|
|
31638
31753
|
parts.push(frameName);
|
|
@@ -31675,7 +31790,7 @@ class PriceMetaService {
|
|
|
31675
31790
|
* Each subject holds the latest currentPrice emitted by the strategy iterator for that key.
|
|
31676
31791
|
* Instances are cached until clear() is called.
|
|
31677
31792
|
*/
|
|
31678
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31793
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$8(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
31679
31794
|
/**
|
|
31680
31795
|
* Returns the current market price for the given symbol and context.
|
|
31681
31796
|
*
|
|
@@ -31704,10 +31819,10 @@ class PriceMetaService {
|
|
|
31704
31819
|
if (source.data) {
|
|
31705
31820
|
return source.data;
|
|
31706
31821
|
}
|
|
31707
|
-
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$
|
|
31822
|
+
console.warn(`PriceMetaService: No currentPrice available for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
31708
31823
|
const currentPrice = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT$1);
|
|
31709
31824
|
if (typeof currentPrice === "symbol") {
|
|
31710
|
-
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$
|
|
31825
|
+
throw new Error(`PriceMetaService: Timeout while waiting for currentPrice for ${CREATE_KEY_FN$8(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31711
31826
|
}
|
|
31712
31827
|
return currentPrice;
|
|
31713
31828
|
};
|
|
@@ -31749,7 +31864,7 @@ class PriceMetaService {
|
|
|
31749
31864
|
this.getSource.clear();
|
|
31750
31865
|
return;
|
|
31751
31866
|
}
|
|
31752
|
-
const key = CREATE_KEY_FN$
|
|
31867
|
+
const key = CREATE_KEY_FN$8(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31753
31868
|
this.getSource.clear(key);
|
|
31754
31869
|
};
|
|
31755
31870
|
}
|
|
@@ -31767,7 +31882,7 @@ const LISTEN_TIMEOUT = 120000;
|
|
|
31767
31882
|
* @param backtest - Whether running in backtest mode
|
|
31768
31883
|
* @returns Unique string key for memoization
|
|
31769
31884
|
*/
|
|
31770
|
-
const CREATE_KEY_FN$
|
|
31885
|
+
const CREATE_KEY_FN$7 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31771
31886
|
const parts = [symbol, strategyName, exchangeName];
|
|
31772
31887
|
if (frameName)
|
|
31773
31888
|
parts.push(frameName);
|
|
@@ -31810,7 +31925,7 @@ class TimeMetaService {
|
|
|
31810
31925
|
* Each subject holds the latest createdAt timestamp emitted by the strategy iterator for that key.
|
|
31811
31926
|
* Instances are cached until clear() is called.
|
|
31812
31927
|
*/
|
|
31813
|
-
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
31928
|
+
this.getSource = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$7(symbol, strategyName, exchangeName, frameName, backtest), () => new functoolsKit.BehaviorSubject());
|
|
31814
31929
|
/**
|
|
31815
31930
|
* Returns the current candle timestamp (in milliseconds) for the given symbol and context.
|
|
31816
31931
|
*
|
|
@@ -31838,10 +31953,10 @@ class TimeMetaService {
|
|
|
31838
31953
|
if (source.data) {
|
|
31839
31954
|
return source.data;
|
|
31840
31955
|
}
|
|
31841
|
-
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$
|
|
31956
|
+
console.warn(`TimeMetaService: No timestamp available for ${CREATE_KEY_FN$7(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}. Trying to fetch from strategy iterator as a fallback...`);
|
|
31842
31957
|
const timestamp = await functoolsKit.waitForNext(source, (data) => !!data, LISTEN_TIMEOUT);
|
|
31843
31958
|
if (typeof timestamp === "symbol") {
|
|
31844
|
-
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$
|
|
31959
|
+
throw new Error(`TimeMetaService: Timeout while waiting for timestamp for ${CREATE_KEY_FN$7(symbol, context.strategyName, context.exchangeName, context.frameName, backtest)}`);
|
|
31845
31960
|
}
|
|
31846
31961
|
return timestamp;
|
|
31847
31962
|
};
|
|
@@ -31883,7 +31998,7 @@ class TimeMetaService {
|
|
|
31883
31998
|
this.getSource.clear();
|
|
31884
31999
|
return;
|
|
31885
32000
|
}
|
|
31886
|
-
const key = CREATE_KEY_FN$
|
|
32001
|
+
const key = CREATE_KEY_FN$7(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
31887
32002
|
this.getSource.clear(key);
|
|
31888
32003
|
};
|
|
31889
32004
|
}
|
|
@@ -31979,7 +32094,7 @@ class MaxDrawdownReportService {
|
|
|
31979
32094
|
/**
|
|
31980
32095
|
* Creates a unique memoization key for a symbol-strategy-exchange-frame-backtest combination.
|
|
31981
32096
|
*/
|
|
31982
|
-
const CREATE_KEY_FN$
|
|
32097
|
+
const CREATE_KEY_FN$6 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
31983
32098
|
const parts = [symbol, strategyName, exchangeName];
|
|
31984
32099
|
if (frameName)
|
|
31985
32100
|
parts.push(frameName);
|
|
@@ -32103,7 +32218,7 @@ class ReportStorage {
|
|
|
32103
32218
|
class MaxDrawdownMarkdownService {
|
|
32104
32219
|
constructor() {
|
|
32105
32220
|
this.loggerService = inject(TYPES.loggerService);
|
|
32106
|
-
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
32221
|
+
this.getStorage = functoolsKit.memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$6(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName) => new ReportStorage(symbol, strategyName, exchangeName, frameName));
|
|
32107
32222
|
/**
|
|
32108
32223
|
* Subscribes to `maxDrawdownSubject` to start receiving `MaxDrawdownContract`
|
|
32109
32224
|
* events. Protected against multiple subscriptions via `singleshot`.
|
|
@@ -32182,7 +32297,7 @@ class MaxDrawdownMarkdownService {
|
|
|
32182
32297
|
this.clear = async (payload) => {
|
|
32183
32298
|
this.loggerService.log("maxDrawdownMarkdownService clear", { payload });
|
|
32184
32299
|
if (payload) {
|
|
32185
|
-
const key = CREATE_KEY_FN$
|
|
32300
|
+
const key = CREATE_KEY_FN$6(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
32186
32301
|
this.getStorage.clear(key);
|
|
32187
32302
|
}
|
|
32188
32303
|
else {
|
|
@@ -45248,6 +45363,503 @@ async function listRiskSchema() {
|
|
|
45248
45363
|
return await backtest.riskValidationService.list();
|
|
45249
45364
|
}
|
|
45250
45365
|
|
|
45366
|
+
const RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistBacktestUtils.handleActivePing";
|
|
45367
|
+
const RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistBacktestUtils.getLatestSignal";
|
|
45368
|
+
const RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistLiveUtils.handleActivePing";
|
|
45369
|
+
const RECENT_PERSIST_LIVE_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistLiveUtils.getLatestSignal";
|
|
45370
|
+
const RECENT_MEMORY_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentMemoryBacktestUtils.handleActivePing";
|
|
45371
|
+
const RECENT_MEMORY_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentMemoryBacktestUtils.getLatestSignal";
|
|
45372
|
+
const RECENT_MEMORY_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentMemoryLiveUtils.handleActivePing";
|
|
45373
|
+
const RECENT_MEMORY_LIVE_METHOD_NAME_GET_LATEST_SIGNAL = "RecentMemoryLiveUtils.getLatestSignal";
|
|
45374
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentBacktestAdapter.handleActivePing";
|
|
45375
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentBacktestAdapter.getLatestSignal";
|
|
45376
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER = "RecentBacktestAdapter.useRecentAdapter";
|
|
45377
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST = "RecentBacktestAdapter.usePersist";
|
|
45378
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY = "RecentBacktestAdapter.useMemory";
|
|
45379
|
+
const RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR = "RecentBacktestAdapter.clear";
|
|
45380
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentLiveAdapter.handleActivePing";
|
|
45381
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentLiveAdapter.getLatestSignal";
|
|
45382
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER = "RecentLiveAdapter.useRecentAdapter";
|
|
45383
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST = "RecentLiveAdapter.usePersist";
|
|
45384
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY = "RecentLiveAdapter.useMemory";
|
|
45385
|
+
const RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR = "RecentLiveAdapter.clear";
|
|
45386
|
+
const RECENT_ADAPTER_METHOD_NAME_ENABLE = "RecentAdapter.enable";
|
|
45387
|
+
const RECENT_ADAPTER_METHOD_NAME_DISABLE = "RecentAdapter.disable";
|
|
45388
|
+
const RECENT_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL = "RecentAdapter.getLatestSignal";
|
|
45389
|
+
/**
|
|
45390
|
+
* Builds a composite storage key from context parts.
|
|
45391
|
+
* Includes backtest flag as the last segment to prevent live/backtest collisions.
|
|
45392
|
+
* @param symbol - Trading pair symbol
|
|
45393
|
+
* @param strategyName - Strategy identifier
|
|
45394
|
+
* @param exchangeName - Exchange identifier
|
|
45395
|
+
* @param frameName - Frame identifier
|
|
45396
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45397
|
+
* @returns Composite key string
|
|
45398
|
+
*/
|
|
45399
|
+
const CREATE_KEY_FN$5 = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
45400
|
+
const parts = [symbol, strategyName, exchangeName];
|
|
45401
|
+
if (frameName)
|
|
45402
|
+
parts.push(frameName);
|
|
45403
|
+
parts.push(backtest ? "backtest" : "live");
|
|
45404
|
+
return parts.join(":");
|
|
45405
|
+
};
|
|
45406
|
+
/**
|
|
45407
|
+
* Persistent storage adapter for backtest recent signals.
|
|
45408
|
+
*
|
|
45409
|
+
* Features:
|
|
45410
|
+
* - Persists the latest active signal per context to disk using PersistRecentAdapter
|
|
45411
|
+
* - Handles active ping events only
|
|
45412
|
+
*
|
|
45413
|
+
* Use this adapter for backtest recent signal persistence across sessions.
|
|
45414
|
+
*/
|
|
45415
|
+
class RecentPersistBacktestUtils {
|
|
45416
|
+
constructor() {
|
|
45417
|
+
/**
|
|
45418
|
+
* Handles active ping event.
|
|
45419
|
+
* Persists the latest signal to disk via PersistRecentAdapter.
|
|
45420
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45421
|
+
*/
|
|
45422
|
+
this.handleActivePing = async (event) => {
|
|
45423
|
+
backtest.loggerService.info(RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45424
|
+
signalId: event.data.id,
|
|
45425
|
+
});
|
|
45426
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45427
|
+
};
|
|
45428
|
+
/**
|
|
45429
|
+
* Retrieves the latest persisted signal for the given context.
|
|
45430
|
+
* @param symbol - Trading pair symbol
|
|
45431
|
+
* @param strategyName - Strategy identifier
|
|
45432
|
+
* @param exchangeName - Exchange identifier
|
|
45433
|
+
* @param frameName - Frame identifier
|
|
45434
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45435
|
+
* @returns The latest signal or null if not found
|
|
45436
|
+
*/
|
|
45437
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45438
|
+
backtest.loggerService.info(RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45439
|
+
symbol,
|
|
45440
|
+
strategyName,
|
|
45441
|
+
exchangeName,
|
|
45442
|
+
frameName,
|
|
45443
|
+
backtest: backtest$1,
|
|
45444
|
+
});
|
|
45445
|
+
return await PersistRecentAdapter.readRecentData(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45446
|
+
};
|
|
45447
|
+
}
|
|
45448
|
+
}
|
|
45449
|
+
/**
|
|
45450
|
+
* In-memory storage adapter for backtest recent signals.
|
|
45451
|
+
*
|
|
45452
|
+
* Features:
|
|
45453
|
+
* - Stores the latest active signal per context key in memory only
|
|
45454
|
+
* - Fast read/write operations
|
|
45455
|
+
* - Data is lost when application restarts
|
|
45456
|
+
*
|
|
45457
|
+
* Use this adapter for testing or when persistence is not required.
|
|
45458
|
+
*/
|
|
45459
|
+
class RecentMemoryBacktestUtils {
|
|
45460
|
+
constructor() {
|
|
45461
|
+
/** Map of composite context keys to the latest signal */
|
|
45462
|
+
this._signals = new Map();
|
|
45463
|
+
/**
|
|
45464
|
+
* Handles active ping event.
|
|
45465
|
+
* Stores the latest signal in memory under the composite context key.
|
|
45466
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45467
|
+
*/
|
|
45468
|
+
this.handleActivePing = async (event) => {
|
|
45469
|
+
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45470
|
+
signalId: event.data.id,
|
|
45471
|
+
});
|
|
45472
|
+
const key = CREATE_KEY_FN$5(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45473
|
+
this._signals.set(key, event.data);
|
|
45474
|
+
};
|
|
45475
|
+
/**
|
|
45476
|
+
* Retrieves the latest in-memory signal for the given context.
|
|
45477
|
+
* @param symbol - Trading pair symbol
|
|
45478
|
+
* @param strategyName - Strategy identifier
|
|
45479
|
+
* @param exchangeName - Exchange identifier
|
|
45480
|
+
* @param frameName - Frame identifier
|
|
45481
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45482
|
+
* @returns The latest signal or null if not found
|
|
45483
|
+
*/
|
|
45484
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45485
|
+
const key = CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45486
|
+
backtest.loggerService.info(RECENT_MEMORY_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
45487
|
+
return this._signals.get(key) ?? null;
|
|
45488
|
+
};
|
|
45489
|
+
}
|
|
45490
|
+
}
|
|
45491
|
+
/**
|
|
45492
|
+
* Persistent storage adapter for live recent signals.
|
|
45493
|
+
*
|
|
45494
|
+
* Features:
|
|
45495
|
+
* - Persists the latest active signal per context to disk using PersistRecentAdapter
|
|
45496
|
+
* - Handles active ping events only
|
|
45497
|
+
*
|
|
45498
|
+
* Use this adapter (default) for live recent signal persistence across sessions.
|
|
45499
|
+
*/
|
|
45500
|
+
class RecentPersistLiveUtils {
|
|
45501
|
+
constructor() {
|
|
45502
|
+
/**
|
|
45503
|
+
* Handles active ping event.
|
|
45504
|
+
* Persists the latest signal to disk via PersistRecentAdapter.
|
|
45505
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45506
|
+
*/
|
|
45507
|
+
this.handleActivePing = async (event) => {
|
|
45508
|
+
backtest.loggerService.info(RECENT_PERSIST_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45509
|
+
signalId: event.data.id,
|
|
45510
|
+
});
|
|
45511
|
+
await PersistRecentAdapter.writeRecentData(event.data, event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45512
|
+
};
|
|
45513
|
+
/**
|
|
45514
|
+
* Retrieves the latest persisted signal for the given context.
|
|
45515
|
+
* @param symbol - Trading pair symbol
|
|
45516
|
+
* @param strategyName - Strategy identifier
|
|
45517
|
+
* @param exchangeName - Exchange identifier
|
|
45518
|
+
* @param frameName - Frame identifier
|
|
45519
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45520
|
+
* @returns The latest signal or null if not found
|
|
45521
|
+
*/
|
|
45522
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45523
|
+
backtest.loggerService.info(RECENT_PERSIST_LIVE_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45524
|
+
symbol,
|
|
45525
|
+
strategyName,
|
|
45526
|
+
exchangeName,
|
|
45527
|
+
frameName,
|
|
45528
|
+
backtest: backtest$1,
|
|
45529
|
+
});
|
|
45530
|
+
return await PersistRecentAdapter.readRecentData(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45531
|
+
};
|
|
45532
|
+
}
|
|
45533
|
+
}
|
|
45534
|
+
/**
|
|
45535
|
+
* In-memory storage adapter for live recent signals.
|
|
45536
|
+
*
|
|
45537
|
+
* Features:
|
|
45538
|
+
* - Stores the latest active signal per context key in memory only
|
|
45539
|
+
* - Fast read/write operations
|
|
45540
|
+
* - Data is lost when application restarts
|
|
45541
|
+
*
|
|
45542
|
+
* Use this adapter for testing or when persistence is not required.
|
|
45543
|
+
*/
|
|
45544
|
+
class RecentMemoryLiveUtils {
|
|
45545
|
+
constructor() {
|
|
45546
|
+
/** Map of composite context keys to the latest signal */
|
|
45547
|
+
this._signals = new Map();
|
|
45548
|
+
/**
|
|
45549
|
+
* Handles active ping event.
|
|
45550
|
+
* Stores the latest signal in memory under the composite context key.
|
|
45551
|
+
* @param event - Active ping contract with signal data and backtest flag
|
|
45552
|
+
*/
|
|
45553
|
+
this.handleActivePing = async (event) => {
|
|
45554
|
+
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45555
|
+
signalId: event.data.id,
|
|
45556
|
+
});
|
|
45557
|
+
const key = CREATE_KEY_FN$5(event.symbol, event.strategyName, event.exchangeName, event.data.frameName, event.backtest);
|
|
45558
|
+
this._signals.set(key, event.data);
|
|
45559
|
+
};
|
|
45560
|
+
/**
|
|
45561
|
+
* Retrieves the latest in-memory signal for the given context.
|
|
45562
|
+
* @param symbol - Trading pair symbol
|
|
45563
|
+
* @param strategyName - Strategy identifier
|
|
45564
|
+
* @param exchangeName - Exchange identifier
|
|
45565
|
+
* @param frameName - Frame identifier
|
|
45566
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45567
|
+
* @returns The latest signal or null if not found
|
|
45568
|
+
*/
|
|
45569
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45570
|
+
const key = CREATE_KEY_FN$5(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45571
|
+
backtest.loggerService.info(RECENT_MEMORY_LIVE_METHOD_NAME_GET_LATEST_SIGNAL, { key });
|
|
45572
|
+
return this._signals.get(key) ?? null;
|
|
45573
|
+
};
|
|
45574
|
+
}
|
|
45575
|
+
}
|
|
45576
|
+
/**
|
|
45577
|
+
* Backtest recent signal adapter with pluggable storage backend.
|
|
45578
|
+
*
|
|
45579
|
+
* Features:
|
|
45580
|
+
* - Adapter pattern for swappable storage implementations
|
|
45581
|
+
* - Default adapter: RecentMemoryBacktestUtils (in-memory storage)
|
|
45582
|
+
* - Alternative adapter: RecentPersistBacktestUtils
|
|
45583
|
+
* - Convenience methods: usePersist(), useMemory()
|
|
45584
|
+
*/
|
|
45585
|
+
class RecentBacktestAdapter {
|
|
45586
|
+
constructor() {
|
|
45587
|
+
/** Internal storage utils instance */
|
|
45588
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45589
|
+
/**
|
|
45590
|
+
* Handles active ping event.
|
|
45591
|
+
* Proxies call to the underlying storage adapter.
|
|
45592
|
+
* @param event - Active ping contract with signal data
|
|
45593
|
+
*/
|
|
45594
|
+
this.handleActivePing = async (event) => {
|
|
45595
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45596
|
+
signalId: event.data.id,
|
|
45597
|
+
});
|
|
45598
|
+
return await this._recentBacktestUtils.handleActivePing(event);
|
|
45599
|
+
};
|
|
45600
|
+
/**
|
|
45601
|
+
* Retrieves the latest signal for the given context.
|
|
45602
|
+
* Proxies call to the underlying storage adapter.
|
|
45603
|
+
* @param symbol - Trading pair symbol
|
|
45604
|
+
* @param strategyName - Strategy identifier
|
|
45605
|
+
* @param exchangeName - Exchange identifier
|
|
45606
|
+
* @param frameName - Frame identifier
|
|
45607
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45608
|
+
* @returns The latest signal or null if not found
|
|
45609
|
+
*/
|
|
45610
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45611
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45612
|
+
symbol,
|
|
45613
|
+
strategyName,
|
|
45614
|
+
exchangeName,
|
|
45615
|
+
frameName,
|
|
45616
|
+
backtest: backtest$1,
|
|
45617
|
+
});
|
|
45618
|
+
return await this._recentBacktestUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45619
|
+
};
|
|
45620
|
+
/**
|
|
45621
|
+
* Sets the storage adapter constructor.
|
|
45622
|
+
* All future storage operations will use this adapter.
|
|
45623
|
+
* @param Ctor - Constructor for recent adapter
|
|
45624
|
+
*/
|
|
45625
|
+
this.useRecentAdapter = (Ctor) => {
|
|
45626
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_ADAPTER);
|
|
45627
|
+
this._recentBacktestUtils = Reflect.construct(Ctor, []);
|
|
45628
|
+
};
|
|
45629
|
+
/**
|
|
45630
|
+
* Switches to persistent storage adapter.
|
|
45631
|
+
* Signals will be persisted to disk.
|
|
45632
|
+
*/
|
|
45633
|
+
this.usePersist = () => {
|
|
45634
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
45635
|
+
this._recentBacktestUtils = new RecentPersistBacktestUtils();
|
|
45636
|
+
};
|
|
45637
|
+
/**
|
|
45638
|
+
* Switches to in-memory storage adapter (default).
|
|
45639
|
+
* Signals will be stored in memory only.
|
|
45640
|
+
*/
|
|
45641
|
+
this.useMemory = () => {
|
|
45642
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_USE_MEMORY);
|
|
45643
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45644
|
+
};
|
|
45645
|
+
/**
|
|
45646
|
+
* Clears the cached utils instance by resetting to the default in-memory adapter.
|
|
45647
|
+
*/
|
|
45648
|
+
this.clear = () => {
|
|
45649
|
+
backtest.loggerService.info(RECENT_BACKTEST_ADAPTER_METHOD_NAME_CLEAR);
|
|
45650
|
+
this._recentBacktestUtils = new RecentMemoryBacktestUtils();
|
|
45651
|
+
};
|
|
45652
|
+
}
|
|
45653
|
+
}
|
|
45654
|
+
/**
|
|
45655
|
+
* Live recent signal adapter with pluggable storage backend.
|
|
45656
|
+
*
|
|
45657
|
+
* Features:
|
|
45658
|
+
* - Adapter pattern for swappable storage implementations
|
|
45659
|
+
* - Default adapter: RecentPersistLiveUtils (persistent storage)
|
|
45660
|
+
* - Alternative adapter: RecentMemoryLiveUtils
|
|
45661
|
+
* - Convenience methods: usePersist(), useMemory()
|
|
45662
|
+
*/
|
|
45663
|
+
class RecentLiveAdapter {
|
|
45664
|
+
constructor() {
|
|
45665
|
+
/** Internal storage utils instance */
|
|
45666
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45667
|
+
/**
|
|
45668
|
+
* Handles active ping event.
|
|
45669
|
+
* Proxies call to the underlying storage adapter.
|
|
45670
|
+
* @param event - Active ping contract with signal data
|
|
45671
|
+
*/
|
|
45672
|
+
this.handleActivePing = async (event) => {
|
|
45673
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_HANDLE_ACTIVE_PING, {
|
|
45674
|
+
signalId: event.data.id,
|
|
45675
|
+
});
|
|
45676
|
+
return await this._recentLiveUtils.handleActivePing(event);
|
|
45677
|
+
};
|
|
45678
|
+
/**
|
|
45679
|
+
* Retrieves the latest signal for the given context.
|
|
45680
|
+
* Proxies call to the underlying storage adapter.
|
|
45681
|
+
* @param symbol - Trading pair symbol
|
|
45682
|
+
* @param strategyName - Strategy identifier
|
|
45683
|
+
* @param exchangeName - Exchange identifier
|
|
45684
|
+
* @param frameName - Frame identifier
|
|
45685
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45686
|
+
* @returns The latest signal or null if not found
|
|
45687
|
+
*/
|
|
45688
|
+
this.getLatestSignal = async (symbol, strategyName, exchangeName, frameName, backtest$1) => {
|
|
45689
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45690
|
+
symbol,
|
|
45691
|
+
strategyName,
|
|
45692
|
+
exchangeName,
|
|
45693
|
+
frameName,
|
|
45694
|
+
backtest: backtest$1,
|
|
45695
|
+
});
|
|
45696
|
+
return await this._recentLiveUtils.getLatestSignal(symbol, strategyName, exchangeName, frameName, backtest$1);
|
|
45697
|
+
};
|
|
45698
|
+
/**
|
|
45699
|
+
* Sets the storage adapter constructor.
|
|
45700
|
+
* All future storage operations will use this adapter.
|
|
45701
|
+
* @param Ctor - Constructor for recent adapter
|
|
45702
|
+
*/
|
|
45703
|
+
this.useRecentAdapter = (Ctor) => {
|
|
45704
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_ADAPTER);
|
|
45705
|
+
this._recentLiveUtils = Reflect.construct(Ctor, []);
|
|
45706
|
+
};
|
|
45707
|
+
/**
|
|
45708
|
+
* Switches to persistent storage adapter (default).
|
|
45709
|
+
* Signals will be persisted to disk.
|
|
45710
|
+
*/
|
|
45711
|
+
this.usePersist = () => {
|
|
45712
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_PERSIST);
|
|
45713
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45714
|
+
};
|
|
45715
|
+
/**
|
|
45716
|
+
* Switches to in-memory storage adapter.
|
|
45717
|
+
* Signals will be stored in memory only.
|
|
45718
|
+
*/
|
|
45719
|
+
this.useMemory = () => {
|
|
45720
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_USE_MEMORY);
|
|
45721
|
+
this._recentLiveUtils = new RecentMemoryLiveUtils();
|
|
45722
|
+
};
|
|
45723
|
+
/**
|
|
45724
|
+
* Clears the cached utils instance by resetting to the default persistent adapter.
|
|
45725
|
+
*/
|
|
45726
|
+
this.clear = () => {
|
|
45727
|
+
backtest.loggerService.info(RECENT_LIVE_ADAPTER_METHOD_NAME_CLEAR);
|
|
45728
|
+
this._recentLiveUtils = new RecentPersistLiveUtils();
|
|
45729
|
+
};
|
|
45730
|
+
}
|
|
45731
|
+
}
|
|
45732
|
+
/**
|
|
45733
|
+
* Main recent signal adapter that manages both backtest and live recent signal storage.
|
|
45734
|
+
*
|
|
45735
|
+
* Features:
|
|
45736
|
+
* - Subscribes to activePingSubject for automatic storage updates
|
|
45737
|
+
* - Provides unified access to the latest signal for any context
|
|
45738
|
+
* - Singleshot enable pattern prevents duplicate subscriptions
|
|
45739
|
+
* - Cleanup function for proper unsubscription
|
|
45740
|
+
*/
|
|
45741
|
+
class RecentAdapter {
|
|
45742
|
+
constructor() {
|
|
45743
|
+
/**
|
|
45744
|
+
* Enables recent signal storage by subscribing to activePingSubject.
|
|
45745
|
+
* Uses singleshot to ensure one-time subscription.
|
|
45746
|
+
*
|
|
45747
|
+
* @returns Cleanup function that unsubscribes from all emitters
|
|
45748
|
+
*/
|
|
45749
|
+
this.enable = functoolsKit.singleshot(() => {
|
|
45750
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_ENABLE);
|
|
45751
|
+
let unBacktest;
|
|
45752
|
+
let unLive;
|
|
45753
|
+
{
|
|
45754
|
+
const unBacktestPingActive = activePingSubject
|
|
45755
|
+
.filter(({ backtest }) => backtest)
|
|
45756
|
+
.connect((event) => RecentBacktest.handleActivePing(event));
|
|
45757
|
+
unBacktest = functoolsKit.compose(() => unBacktestPingActive());
|
|
45758
|
+
}
|
|
45759
|
+
{
|
|
45760
|
+
const unLivePingActive = activePingSubject
|
|
45761
|
+
.filter(({ backtest }) => !backtest)
|
|
45762
|
+
.connect((event) => RecentLive.handleActivePing(event));
|
|
45763
|
+
unLive = functoolsKit.compose(() => unLivePingActive());
|
|
45764
|
+
}
|
|
45765
|
+
const unEnable = () => this.enable.clear();
|
|
45766
|
+
return functoolsKit.compose(() => unBacktest(), () => unLive(), () => unEnable());
|
|
45767
|
+
});
|
|
45768
|
+
/**
|
|
45769
|
+
* Disables recent signal storage by unsubscribing from all emitters.
|
|
45770
|
+
* Safe to call multiple times.
|
|
45771
|
+
*/
|
|
45772
|
+
this.disable = () => {
|
|
45773
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_DISABLE);
|
|
45774
|
+
if (this.enable.hasValue()) {
|
|
45775
|
+
const lastSubscription = this.enable();
|
|
45776
|
+
lastSubscription();
|
|
45777
|
+
}
|
|
45778
|
+
};
|
|
45779
|
+
/**
|
|
45780
|
+
* Retrieves the latest active signal for the given symbol and context.
|
|
45781
|
+
* Searches backtest storage first, then live storage.
|
|
45782
|
+
*
|
|
45783
|
+
* @param symbol - Trading pair symbol
|
|
45784
|
+
* @param context - Execution context with strategyName, exchangeName, and frameName
|
|
45785
|
+
* @param backtest - Flag indicating if the context is backtest or live
|
|
45786
|
+
* @returns The latest signal or null if not found
|
|
45787
|
+
* @throws Error if RecentAdapter is not enabled
|
|
45788
|
+
*/
|
|
45789
|
+
this.getLatestSignal = async (symbol, context) => {
|
|
45790
|
+
backtest.loggerService.info(RECENT_ADAPTER_METHOD_NAME_GET_LATEST_SIGNAL, {
|
|
45791
|
+
symbol,
|
|
45792
|
+
context,
|
|
45793
|
+
});
|
|
45794
|
+
if (!this.enable.hasValue()) {
|
|
45795
|
+
throw new Error("RecentAdapter is not enabled. Call enable() first.");
|
|
45796
|
+
}
|
|
45797
|
+
let result = null;
|
|
45798
|
+
if (result = await RecentBacktest.getLatestSignal(symbol, context.strategyName, context.exchangeName, context.frameName, true)) {
|
|
45799
|
+
return result;
|
|
45800
|
+
}
|
|
45801
|
+
if (result = await RecentLive.getLatestSignal(symbol, context.strategyName, context.exchangeName, context.frameName, false)) {
|
|
45802
|
+
return result;
|
|
45803
|
+
}
|
|
45804
|
+
return null;
|
|
45805
|
+
};
|
|
45806
|
+
}
|
|
45807
|
+
}
|
|
45808
|
+
/**
|
|
45809
|
+
* Global singleton instance of RecentAdapter.
|
|
45810
|
+
* Provides unified recent signal management for backtest and live trading.
|
|
45811
|
+
*/
|
|
45812
|
+
const Recent = new RecentAdapter();
|
|
45813
|
+
/**
|
|
45814
|
+
* Global singleton instance of RecentLiveAdapter.
|
|
45815
|
+
* Provides live trading recent signal storage with pluggable backends.
|
|
45816
|
+
*/
|
|
45817
|
+
const RecentLive = new RecentLiveAdapter();
|
|
45818
|
+
/**
|
|
45819
|
+
* Global singleton instance of RecentBacktestAdapter.
|
|
45820
|
+
* Provides backtest recent signal storage with pluggable backends.
|
|
45821
|
+
*/
|
|
45822
|
+
const RecentBacktest = new RecentBacktestAdapter();
|
|
45823
|
+
|
|
45824
|
+
const GET_LATEST_SIGNAL_METHOD_NAME = "signal.getLatestSignal";
|
|
45825
|
+
/**
|
|
45826
|
+
* Returns the latest signal (pending or closed) for the current strategy context.
|
|
45827
|
+
*
|
|
45828
|
+
* Does not distinguish between active and closed signals — returns whichever
|
|
45829
|
+
* was recorded last. Useful for cooldown logic: e.g. skip opening a new position
|
|
45830
|
+
* for 4 hours after a stop-loss by checking the timestamp of the latest signal
|
|
45831
|
+
* regardless of its outcome.
|
|
45832
|
+
*
|
|
45833
|
+
* Searches backtest storage first, then live storage.
|
|
45834
|
+
* Returns null if no signal exists at all.
|
|
45835
|
+
*
|
|
45836
|
+
* Automatically detects backtest/live mode from execution context.
|
|
45837
|
+
*
|
|
45838
|
+
* @param symbol - Trading pair symbol
|
|
45839
|
+
* @returns Promise resolving to the latest signal or null
|
|
45840
|
+
*
|
|
45841
|
+
* @example
|
|
45842
|
+
* ```typescript
|
|
45843
|
+
* import { getLatestSignal } from "backtest-kit";
|
|
45844
|
+
*
|
|
45845
|
+
* const latest = await getLatestSignal("BTCUSDT");
|
|
45846
|
+
* if (latest && Date.now() - latest.closedAt < 4 * 60 * 60 * 1000) {
|
|
45847
|
+
* return; // cooldown after SL — skip new signal for 4 hours
|
|
45848
|
+
* }
|
|
45849
|
+
* ```
|
|
45850
|
+
*/
|
|
45851
|
+
async function getLatestSignal(symbol) {
|
|
45852
|
+
backtest.loggerService.info(GET_LATEST_SIGNAL_METHOD_NAME, { symbol });
|
|
45853
|
+
if (!ExecutionContextService.hasContext()) {
|
|
45854
|
+
throw new Error("getLatestSignal requires an execution context");
|
|
45855
|
+
}
|
|
45856
|
+
if (!MethodContextService.hasContext()) {
|
|
45857
|
+
throw new Error("getLatestSignal requires a method context");
|
|
45858
|
+
}
|
|
45859
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
45860
|
+
return await Recent.getLatestSignal(symbol, { exchangeName, frameName, strategyName });
|
|
45861
|
+
}
|
|
45862
|
+
|
|
45251
45863
|
const DEFAULT_BM25_K1 = 1.5;
|
|
45252
45864
|
const DEFAULT_BM25_B = 0.75;
|
|
45253
45865
|
const DEFAULT_BM25_SCORE = 0.5;
|
|
@@ -48498,6 +49110,67 @@ class LogAdapter {
|
|
|
48498
49110
|
*/
|
|
48499
49111
|
const Log = new LogAdapter();
|
|
48500
49112
|
|
|
49113
|
+
const METHOD_NAME_CREATE_SNAPSHOT = "SessionUtils.createSnapshot";
|
|
49114
|
+
/** List of all global subjects whose listeners should be snapshotted for session isolation */
|
|
49115
|
+
const SUBJECT_ISOLATION_LIST = [
|
|
49116
|
+
activePingSubject,
|
|
49117
|
+
backtestScheduleOpenSubject,
|
|
49118
|
+
breakevenSubject,
|
|
49119
|
+
doneBacktestSubject,
|
|
49120
|
+
doneLiveSubject,
|
|
49121
|
+
errorEmitter,
|
|
49122
|
+
exitEmitter,
|
|
49123
|
+
highestProfitSubject,
|
|
49124
|
+
maxDrawdownSubject,
|
|
49125
|
+
partialLossSubject,
|
|
49126
|
+
partialProfitSubject,
|
|
49127
|
+
performanceEmitter,
|
|
49128
|
+
progressBacktestEmitter,
|
|
49129
|
+
riskSubject,
|
|
49130
|
+
schedulePingSubject,
|
|
49131
|
+
shutdownEmitter,
|
|
49132
|
+
signalBacktestEmitter,
|
|
49133
|
+
signalEmitter,
|
|
49134
|
+
signalLiveEmitter,
|
|
49135
|
+
strategyCommitSubject,
|
|
49136
|
+
syncSubject,
|
|
49137
|
+
validationSubject,
|
|
49138
|
+
];
|
|
49139
|
+
/**
|
|
49140
|
+
* Creates a snapshot function for a given subject by clearing its internal
|
|
49141
|
+
* events map and returning a restore function that can put the original listeners back.
|
|
49142
|
+
* @param subject The subject to snapshot
|
|
49143
|
+
* @returns A function that restores the subject's original listeners when called
|
|
49144
|
+
*/
|
|
49145
|
+
const CREATE_SUBJECT_SNAPSHOT_FN = (subject) => {
|
|
49146
|
+
const emitter = subject["_emitter"];
|
|
49147
|
+
const events = emitter["_events"];
|
|
49148
|
+
emitter["_events"] = {};
|
|
49149
|
+
return () => {
|
|
49150
|
+
emitter["_events"] = events;
|
|
49151
|
+
};
|
|
49152
|
+
};
|
|
49153
|
+
/**
|
|
49154
|
+
* Manages isolation of global event-bus state between backtest sessions.
|
|
49155
|
+
* Allows temporarily detaching all subject subscriptions so that one session
|
|
49156
|
+
* does not interfere with another, then restoring them afterwards.
|
|
49157
|
+
*/
|
|
49158
|
+
class SessionUtils {
|
|
49159
|
+
constructor() {
|
|
49160
|
+
/**
|
|
49161
|
+
* Snapshots the current listener state of every global subject by replacing
|
|
49162
|
+
* their internal `_events` map with an empty object.
|
|
49163
|
+
* @returns A restore function that, when called, puts all original listeners back.
|
|
49164
|
+
*/
|
|
49165
|
+
this.createSnapshot = () => {
|
|
49166
|
+
backtest.loggerService.log(METHOD_NAME_CREATE_SNAPSHOT);
|
|
49167
|
+
const snapshotList = SUBJECT_ISOLATION_LIST.map(CREATE_SUBJECT_SNAPSHOT_FN);
|
|
49168
|
+
return functoolsKit.compose(...snapshotList);
|
|
49169
|
+
};
|
|
49170
|
+
}
|
|
49171
|
+
}
|
|
49172
|
+
const Session = new SessionUtils();
|
|
49173
|
+
|
|
48501
49174
|
const SCHEDULE_METHOD_NAME_GET_DATA = "ScheduleUtils.getData";
|
|
48502
49175
|
const SCHEDULE_METHOD_NAME_GET_REPORT = "ScheduleUtils.getReport";
|
|
48503
49176
|
const SCHEDULE_METHOD_NAME_DUMP = "ScheduleUtils.dump";
|
|
@@ -54735,12 +55408,15 @@ const CACHE_METHOD_NAME_RUN = "CacheFnInstance.run";
|
|
|
54735
55408
|
const CACHE_METHOD_NAME_FN = "CacheUtils.fn";
|
|
54736
55409
|
const CACHE_METHOD_NAME_FN_CLEAR = "CacheUtils.fn.clear";
|
|
54737
55410
|
const CACHE_METHOD_NAME_FN_GC = "CacheUtils.fn.gc";
|
|
55411
|
+
const CACHE_METHOD_NAME_FN_HAS_VALUE = "CacheUtils.fn.hasValue";
|
|
54738
55412
|
const CACHE_METHOD_NAME_FILE = "CacheUtils.file";
|
|
54739
55413
|
const CACHE_METHOD_NAME_FILE_CLEAR = "CacheUtils.file.clear";
|
|
55414
|
+
const CACHE_METHOD_NAME_FILE_HAS_VALUE = "CacheUtils.file.hasValue";
|
|
54740
55415
|
const CACHE_METHOD_NAME_DISPOSE = "CacheUtils.dispose";
|
|
54741
55416
|
const CACHE_METHOD_NAME_CLEAR = "CacheUtils.clear";
|
|
54742
55417
|
const CACHE_METHOD_NAME_RESET_COUNTER = "CacheUtils.resetCounter";
|
|
54743
55418
|
const CACHE_FILE_INSTANCE_METHOD_NAME_RUN = "CacheFileInstance.run";
|
|
55419
|
+
const CACHE_FILE_INSTANCE_METHOD_NAME_HAS_VALUE = "CacheFileInstance.hasValue";
|
|
54744
55420
|
const MS_PER_MINUTE$1 = 60000;
|
|
54745
55421
|
const INTERVAL_MINUTES$1 = {
|
|
54746
55422
|
"1m": 1,
|
|
@@ -54930,6 +55606,36 @@ class CacheFnInstance {
|
|
|
54930
55606
|
}
|
|
54931
55607
|
}
|
|
54932
55608
|
};
|
|
55609
|
+
/**
|
|
55610
|
+
* Check whether a valid (non-expired) cache entry exists for the current context and arguments.
|
|
55611
|
+
*
|
|
55612
|
+
* Returns `true` if a cached value exists and its interval is still current.
|
|
55613
|
+
* Returns `false` if there is no entry or the cached entry has expired.
|
|
55614
|
+
*
|
|
55615
|
+
* Requires active execution context and method context.
|
|
55616
|
+
*
|
|
55617
|
+
* @param args - Arguments to look up in the cache
|
|
55618
|
+
* @returns `true` if a fresh cached value exists, `false` otherwise
|
|
55619
|
+
*/
|
|
55620
|
+
this.hasValue = (...args) => {
|
|
55621
|
+
if (!MethodContextService.hasContext()) {
|
|
55622
|
+
throw new Error("CacheFnInstance hasValue requires method context");
|
|
55623
|
+
}
|
|
55624
|
+
if (!ExecutionContextService.hasContext()) {
|
|
55625
|
+
throw new Error("CacheFnInstance hasValue requires execution context");
|
|
55626
|
+
}
|
|
55627
|
+
const contextKey = CREATE_KEY_FN$1(backtest.methodContextService.context.strategyName, backtest.methodContextService.context.exchangeName, backtest.methodContextService.context.frameName, backtest.executionContextService.context.backtest);
|
|
55628
|
+
const argKey = String(this.key(args));
|
|
55629
|
+
const key = `${contextKey}:${argKey}`;
|
|
55630
|
+
const cached = this._cacheMap.get(key);
|
|
55631
|
+
if (!cached) {
|
|
55632
|
+
return false;
|
|
55633
|
+
}
|
|
55634
|
+
const currentWhen = backtest.executionContextService.context.when;
|
|
55635
|
+
const currentAligned = align$1(currentWhen.getTime(), this.interval);
|
|
55636
|
+
const cachedAligned = align$1(cached.when.getTime(), this.interval);
|
|
55637
|
+
return currentAligned === cachedAligned;
|
|
55638
|
+
};
|
|
54933
55639
|
/**
|
|
54934
55640
|
* Garbage collect expired cache entries.
|
|
54935
55641
|
*
|
|
@@ -55054,6 +55760,33 @@ class CacheFileInstance {
|
|
|
55054
55760
|
await PersistMeasureAdapter.writeMeasureData({ id: entityKey, data: result, removed: false }, bucket, entityKey);
|
|
55055
55761
|
return result;
|
|
55056
55762
|
};
|
|
55763
|
+
/**
|
|
55764
|
+
* Check whether a cached value exists on disk for the given arguments and current interval.
|
|
55765
|
+
*
|
|
55766
|
+
* Returns `true` if a persisted record exists for the current aligned timestamp.
|
|
55767
|
+
* Returns `false` if no record is found.
|
|
55768
|
+
*
|
|
55769
|
+
* Requires active execution context and method context.
|
|
55770
|
+
*
|
|
55771
|
+
* @param args - Arguments forwarded to the key generator
|
|
55772
|
+
* @returns `true` if a cached record exists, `false` otherwise
|
|
55773
|
+
*/
|
|
55774
|
+
this.hasValue = async (...args) => {
|
|
55775
|
+
backtest.loggerService.debug(CACHE_FILE_INSTANCE_METHOD_NAME_HAS_VALUE, { args });
|
|
55776
|
+
if (!MethodContextService.hasContext()) {
|
|
55777
|
+
throw new Error("CacheFileInstance hasValue requires method context");
|
|
55778
|
+
}
|
|
55779
|
+
if (!ExecutionContextService.hasContext()) {
|
|
55780
|
+
throw new Error("CacheFileInstance hasValue requires execution context");
|
|
55781
|
+
}
|
|
55782
|
+
const [symbol, ...rest] = args;
|
|
55783
|
+
const { when } = backtest.executionContextService.context;
|
|
55784
|
+
const alignedTs = align$1(when.getTime(), this.interval);
|
|
55785
|
+
const bucket = `${this.name}_${this.interval}_${this.index}`;
|
|
55786
|
+
const entityKey = this.key([symbol, alignedTs, ...rest]);
|
|
55787
|
+
const cached = await PersistMeasureAdapter.readMeasureData(bucket, entityKey);
|
|
55788
|
+
return cached !== null;
|
|
55789
|
+
};
|
|
55057
55790
|
/**
|
|
55058
55791
|
* Soft-delete all persisted records for this instance's bucket.
|
|
55059
55792
|
* After this call the next `run()` will recompute and re-cache the value.
|
|
@@ -55140,23 +55873,30 @@ class CacheUtils {
|
|
|
55140
55873
|
wrappedFn.clear = () => {
|
|
55141
55874
|
backtest.loggerService.info(CACHE_METHOD_NAME_FN_CLEAR);
|
|
55142
55875
|
if (!MethodContextService.hasContext()) {
|
|
55143
|
-
|
|
55144
|
-
return;
|
|
55876
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_CLEAR} requires method context`);
|
|
55145
55877
|
}
|
|
55146
55878
|
if (!ExecutionContextService.hasContext()) {
|
|
55147
|
-
|
|
55148
|
-
return;
|
|
55879
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_CLEAR} requires execution context`);
|
|
55149
55880
|
}
|
|
55150
55881
|
this._getFnInstance.get(run)?.clear();
|
|
55151
55882
|
};
|
|
55152
55883
|
wrappedFn.gc = () => {
|
|
55153
55884
|
backtest.loggerService.info(CACHE_METHOD_NAME_FN_GC);
|
|
55154
55885
|
if (!ExecutionContextService.hasContext()) {
|
|
55155
|
-
|
|
55156
|
-
return;
|
|
55886
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_GC} requires execution context`);
|
|
55157
55887
|
}
|
|
55158
55888
|
return this._getFnInstance.get(run)?.gc();
|
|
55159
55889
|
};
|
|
55890
|
+
wrappedFn.hasValue = (...args) => {
|
|
55891
|
+
backtest.loggerService.info(CACHE_METHOD_NAME_FN_HAS_VALUE);
|
|
55892
|
+
if (!MethodContextService.hasContext()) {
|
|
55893
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_HAS_VALUE} requires method context`);
|
|
55894
|
+
}
|
|
55895
|
+
if (!ExecutionContextService.hasContext()) {
|
|
55896
|
+
throw new Error(`${CACHE_METHOD_NAME_FN_HAS_VALUE} requires execution context`);
|
|
55897
|
+
}
|
|
55898
|
+
return this._getFnInstance.get(run)?.hasValue(...args) ?? false;
|
|
55899
|
+
};
|
|
55160
55900
|
return wrappedFn;
|
|
55161
55901
|
};
|
|
55162
55902
|
/**
|
|
@@ -55208,8 +55948,25 @@ class CacheUtils {
|
|
|
55208
55948
|
};
|
|
55209
55949
|
wrappedFn.clear = async () => {
|
|
55210
55950
|
backtest.loggerService.info(CACHE_METHOD_NAME_FILE_CLEAR);
|
|
55951
|
+
if (!MethodContextService.hasContext()) {
|
|
55952
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_CLEAR} requires method context`);
|
|
55953
|
+
}
|
|
55954
|
+
if (!ExecutionContextService.hasContext()) {
|
|
55955
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_CLEAR} requires execution context`);
|
|
55956
|
+
}
|
|
55211
55957
|
await this._getFileInstance.get(run)?.clear();
|
|
55212
55958
|
};
|
|
55959
|
+
wrappedFn.hasValue = async (...args) => {
|
|
55960
|
+
backtest.loggerService.info(CACHE_METHOD_NAME_FILE_HAS_VALUE);
|
|
55961
|
+
if (!MethodContextService.hasContext()) {
|
|
55962
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_HAS_VALUE} requires method context`);
|
|
55963
|
+
}
|
|
55964
|
+
if (!ExecutionContextService.hasContext()) {
|
|
55965
|
+
throw new Error(`${CACHE_METHOD_NAME_FILE_HAS_VALUE} requires execution context`);
|
|
55966
|
+
}
|
|
55967
|
+
const instance = this._getFileInstance(run, context.interval, context.name, context.key);
|
|
55968
|
+
return await instance.hasValue(...args);
|
|
55969
|
+
};
|
|
55213
55970
|
return wrappedFn;
|
|
55214
55971
|
};
|
|
55215
55972
|
/**
|
|
@@ -55278,11 +56035,14 @@ const Cache = new CacheUtils();
|
|
|
55278
56035
|
|
|
55279
56036
|
const INTERVAL_METHOD_NAME_RUN = "IntervalFnInstance.run";
|
|
55280
56037
|
const INTERVAL_FILE_INSTANCE_METHOD_NAME_RUN = "IntervalFileInstance.run";
|
|
56038
|
+
const INTERVAL_FILE_INSTANCE_METHOD_NAME_HAS_VALUE = "IntervalFileInstance.hasValue";
|
|
55281
56039
|
const INTERVAL_METHOD_NAME_FN = "IntervalUtils.fn";
|
|
55282
56040
|
const INTERVAL_METHOD_NAME_FN_CLEAR = "IntervalUtils.fn.clear";
|
|
55283
56041
|
const INTERVAL_METHOD_NAME_FN_GC = "IntervalUtils.fn.gc";
|
|
56042
|
+
const INTERVAL_METHOD_NAME_FN_HAS_VALUE = "IntervalUtils.fn.hasValue";
|
|
55284
56043
|
const INTERVAL_METHOD_NAME_FILE = "IntervalUtils.file";
|
|
55285
56044
|
const INTERVAL_METHOD_NAME_FILE_CLEAR = "IntervalUtils.file.clear";
|
|
56045
|
+
const INTERVAL_METHOD_NAME_FILE_HAS_VALUE = "IntervalUtils.file.hasValue";
|
|
55286
56046
|
const INTERVAL_METHOD_NAME_DISPOSE = "IntervalUtils.dispose";
|
|
55287
56047
|
const INTERVAL_METHOD_NAME_CLEAR = "IntervalUtils.clear";
|
|
55288
56048
|
const INTERVAL_METHOD_NAME_RESET_COUNTER = "IntervalUtils.resetCounter";
|
|
@@ -55440,6 +56200,31 @@ class IntervalFnInstance {
|
|
|
55440
56200
|
}
|
|
55441
56201
|
}
|
|
55442
56202
|
};
|
|
56203
|
+
/**
|
|
56204
|
+
* Check whether the function has already fired for the current interval and context.
|
|
56205
|
+
*
|
|
56206
|
+
* Returns `true` if the function fired (non-null result) within the current interval boundary.
|
|
56207
|
+
* Returns `false` if there is no recorded firing for this interval.
|
|
56208
|
+
*
|
|
56209
|
+
* Requires active method context and execution context.
|
|
56210
|
+
*
|
|
56211
|
+
* @param args - Arguments to look up in the state map
|
|
56212
|
+
* @returns `true` if the function has already fired this interval, `false` otherwise
|
|
56213
|
+
*/
|
|
56214
|
+
this.hasValue = (...args) => {
|
|
56215
|
+
if (!MethodContextService.hasContext()) {
|
|
56216
|
+
throw new Error("IntervalFnInstance hasValue requires method context");
|
|
56217
|
+
}
|
|
56218
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56219
|
+
throw new Error("IntervalFnInstance hasValue requires execution context");
|
|
56220
|
+
}
|
|
56221
|
+
const contextKey = CREATE_KEY_FN(backtest.methodContextService.context.strategyName, backtest.methodContextService.context.exchangeName, backtest.methodContextService.context.frameName, backtest.executionContextService.context.backtest);
|
|
56222
|
+
const currentWhen = backtest.executionContextService.context.when;
|
|
56223
|
+
const currentAligned = align(currentWhen.getTime(), this.interval);
|
|
56224
|
+
const argKey = this.key(args);
|
|
56225
|
+
const stateKey = `${contextKey}:${argKey}`;
|
|
56226
|
+
return this._stateMap.get(stateKey) === currentAligned;
|
|
56227
|
+
};
|
|
55443
56228
|
/**
|
|
55444
56229
|
* Garbage collect expired state entries.
|
|
55445
56230
|
*
|
|
@@ -55561,6 +56346,33 @@ class IntervalFileInstance {
|
|
|
55561
56346
|
}
|
|
55562
56347
|
return result;
|
|
55563
56348
|
};
|
|
56349
|
+
/**
|
|
56350
|
+
* Check whether the function has already fired for the current interval on disk.
|
|
56351
|
+
*
|
|
56352
|
+
* Returns `true` if a persisted record exists for the current aligned timestamp.
|
|
56353
|
+
* Returns `false` if no record is found.
|
|
56354
|
+
*
|
|
56355
|
+
* Requires active execution context and method context.
|
|
56356
|
+
*
|
|
56357
|
+
* @param args - Arguments forwarded to the key generator
|
|
56358
|
+
* @returns `true` if a fired record exists, `false` otherwise
|
|
56359
|
+
*/
|
|
56360
|
+
this.hasValue = async (...args) => {
|
|
56361
|
+
backtest.loggerService.debug(INTERVAL_FILE_INSTANCE_METHOD_NAME_HAS_VALUE, { args });
|
|
56362
|
+
if (!MethodContextService.hasContext()) {
|
|
56363
|
+
throw new Error("IntervalFileInstance hasValue requires method context");
|
|
56364
|
+
}
|
|
56365
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56366
|
+
throw new Error("IntervalFileInstance hasValue requires execution context");
|
|
56367
|
+
}
|
|
56368
|
+
const [symbol, ...rest] = args;
|
|
56369
|
+
const { when } = backtest.executionContextService.context;
|
|
56370
|
+
const alignedMs = align(when.getTime(), this.interval);
|
|
56371
|
+
const bucket = `${this.name}_${this.interval}_${this.index}`;
|
|
56372
|
+
const entityKey = this.key([symbol, alignedMs, ...rest]);
|
|
56373
|
+
const cached = await PersistIntervalAdapter.readIntervalData(bucket, entityKey);
|
|
56374
|
+
return cached !== null;
|
|
56375
|
+
};
|
|
55564
56376
|
/**
|
|
55565
56377
|
* Soft-delete all persisted records for this instance's bucket.
|
|
55566
56378
|
* After this call the function will fire again on the next `run()`.
|
|
@@ -55641,23 +56453,30 @@ class IntervalUtils {
|
|
|
55641
56453
|
wrappedFn.clear = () => {
|
|
55642
56454
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_CLEAR);
|
|
55643
56455
|
if (!MethodContextService.hasContext()) {
|
|
55644
|
-
|
|
55645
|
-
return;
|
|
56456
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_CLEAR} requires method context`);
|
|
55646
56457
|
}
|
|
55647
56458
|
if (!ExecutionContextService.hasContext()) {
|
|
55648
|
-
|
|
55649
|
-
return;
|
|
56459
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_CLEAR} requires execution context`);
|
|
55650
56460
|
}
|
|
55651
56461
|
this._getInstance.get(run)?.clear();
|
|
55652
56462
|
};
|
|
55653
56463
|
wrappedFn.gc = () => {
|
|
55654
56464
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_GC);
|
|
55655
56465
|
if (!ExecutionContextService.hasContext()) {
|
|
55656
|
-
|
|
55657
|
-
return;
|
|
56466
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_GC} requires execution context`);
|
|
55658
56467
|
}
|
|
55659
56468
|
return this._getInstance.get(run)?.gc();
|
|
55660
56469
|
};
|
|
56470
|
+
wrappedFn.hasValue = (...args) => {
|
|
56471
|
+
backtest.loggerService.info(INTERVAL_METHOD_NAME_FN_HAS_VALUE);
|
|
56472
|
+
if (!MethodContextService.hasContext()) {
|
|
56473
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_HAS_VALUE} requires method context`);
|
|
56474
|
+
}
|
|
56475
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56476
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FN_HAS_VALUE} requires execution context`);
|
|
56477
|
+
}
|
|
56478
|
+
return this._getInstance.get(run)?.hasValue(...args) ?? false;
|
|
56479
|
+
};
|
|
55661
56480
|
return wrappedFn;
|
|
55662
56481
|
};
|
|
55663
56482
|
/**
|
|
@@ -55700,8 +56519,25 @@ class IntervalUtils {
|
|
|
55700
56519
|
};
|
|
55701
56520
|
wrappedFn.clear = async () => {
|
|
55702
56521
|
backtest.loggerService.info(INTERVAL_METHOD_NAME_FILE_CLEAR);
|
|
56522
|
+
if (!MethodContextService.hasContext()) {
|
|
56523
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_CLEAR} requires method context`);
|
|
56524
|
+
}
|
|
56525
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56526
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_CLEAR} requires execution context`);
|
|
56527
|
+
}
|
|
55703
56528
|
await this._getFileInstance.get(run)?.clear();
|
|
55704
56529
|
};
|
|
56530
|
+
wrappedFn.hasValue = async (...args) => {
|
|
56531
|
+
backtest.loggerService.info(INTERVAL_METHOD_NAME_FILE_HAS_VALUE);
|
|
56532
|
+
if (!MethodContextService.hasContext()) {
|
|
56533
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_HAS_VALUE} requires method context`);
|
|
56534
|
+
}
|
|
56535
|
+
if (!ExecutionContextService.hasContext()) {
|
|
56536
|
+
throw new Error(`${INTERVAL_METHOD_NAME_FILE_HAS_VALUE} requires execution context`);
|
|
56537
|
+
}
|
|
56538
|
+
const instance = this._getFileInstance(run, context.interval, context.name, context.key);
|
|
56539
|
+
return await instance.hasValue(...args);
|
|
56540
|
+
};
|
|
55705
56541
|
return wrappedFn;
|
|
55706
56542
|
};
|
|
55707
56543
|
/**
|
|
@@ -56911,18 +57747,23 @@ exports.PersistMeasureAdapter = PersistMeasureAdapter;
|
|
|
56911
57747
|
exports.PersistMemoryAdapter = PersistMemoryAdapter;
|
|
56912
57748
|
exports.PersistNotificationAdapter = PersistNotificationAdapter;
|
|
56913
57749
|
exports.PersistPartialAdapter = PersistPartialAdapter;
|
|
57750
|
+
exports.PersistRecentAdapter = PersistRecentAdapter;
|
|
56914
57751
|
exports.PersistRiskAdapter = PersistRiskAdapter;
|
|
56915
57752
|
exports.PersistScheduleAdapter = PersistScheduleAdapter;
|
|
56916
57753
|
exports.PersistSignalAdapter = PersistSignalAdapter;
|
|
56917
57754
|
exports.PersistStorageAdapter = PersistStorageAdapter;
|
|
56918
57755
|
exports.Position = Position;
|
|
56919
57756
|
exports.PositionSize = PositionSize;
|
|
57757
|
+
exports.Recent = Recent;
|
|
57758
|
+
exports.RecentBacktest = RecentBacktest;
|
|
57759
|
+
exports.RecentLive = RecentLive;
|
|
56920
57760
|
exports.Reflect = Reflect$1;
|
|
56921
57761
|
exports.Report = Report;
|
|
56922
57762
|
exports.ReportBase = ReportBase;
|
|
56923
57763
|
exports.ReportWriter = ReportWriter;
|
|
56924
57764
|
exports.Risk = Risk;
|
|
56925
57765
|
exports.Schedule = Schedule;
|
|
57766
|
+
exports.Session = Session;
|
|
56926
57767
|
exports.Storage = Storage;
|
|
56927
57768
|
exports.StorageBacktest = StorageBacktest;
|
|
56928
57769
|
exports.StorageLive = StorageLive;
|
|
@@ -56976,6 +57817,7 @@ exports.getDefaultConfig = getDefaultConfig;
|
|
|
56976
57817
|
exports.getEffectivePriceOpen = getEffectivePriceOpen;
|
|
56977
57818
|
exports.getExchangeSchema = getExchangeSchema;
|
|
56978
57819
|
exports.getFrameSchema = getFrameSchema;
|
|
57820
|
+
exports.getLatestSignal = getLatestSignal;
|
|
56979
57821
|
exports.getMaxDrawdownDistancePnlCost = getMaxDrawdownDistancePnlCost;
|
|
56980
57822
|
exports.getMaxDrawdownDistancePnlPercentage = getMaxDrawdownDistancePnlPercentage;
|
|
56981
57823
|
exports.getMode = getMode;
|