backtest-kit 11.7.0 → 11.9.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/README.md +3 -3
- package/build/index.cjs +624 -173
- package/build/index.mjs +624 -174
- package/package.json +1 -1
- package/types.d.ts +304 -51
package/build/index.mjs
CHANGED
|
@@ -74,6 +74,7 @@ const metaServices$1 = {
|
|
|
74
74
|
contextMetaService: Symbol('contextMetaService'),
|
|
75
75
|
priceMetaService: Symbol('priceMetaService'),
|
|
76
76
|
timeMetaService: Symbol('timeMetaService'),
|
|
77
|
+
runtimeMetaService: Symbol('runtimeMetaService'),
|
|
77
78
|
};
|
|
78
79
|
const globalServices$1 = {
|
|
79
80
|
sizingGlobalService: Symbol('sizingGlobalService'),
|
|
@@ -4660,7 +4661,7 @@ const LOGGER_SERVICE$8 = new LoggerService();
|
|
|
4660
4661
|
* @param backtest - `true` for backtest, `false` for live.
|
|
4661
4662
|
* @returns Colon-joined composite key.
|
|
4662
4663
|
*/
|
|
4663
|
-
const CREATE_KEY_FN$
|
|
4664
|
+
const CREATE_KEY_FN$B = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
4664
4665
|
const parts = [symbol, strategyName, exchangeName];
|
|
4665
4666
|
if (frameName)
|
|
4666
4667
|
parts.push(frameName);
|
|
@@ -4703,7 +4704,7 @@ class LookupUtils {
|
|
|
4703
4704
|
LOGGER_SERVICE$8.info(METHOD_NAME_ADD_ACTIVITY, {
|
|
4704
4705
|
activity,
|
|
4705
4706
|
});
|
|
4706
|
-
const key = CREATE_KEY_FN$
|
|
4707
|
+
const key = CREATE_KEY_FN$B(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4707
4708
|
this._lookupMap.set(key, activity);
|
|
4708
4709
|
};
|
|
4709
4710
|
/**
|
|
@@ -4717,7 +4718,7 @@ class LookupUtils {
|
|
|
4717
4718
|
LOGGER_SERVICE$8.info(METHOD_NAME_REMOVE_ACTIVITY, {
|
|
4718
4719
|
activity,
|
|
4719
4720
|
});
|
|
4720
|
-
const key = CREATE_KEY_FN$
|
|
4721
|
+
const key = CREATE_KEY_FN$B(activity.symbol, activity.context.strategyName, activity.context.exchangeName, activity.context.frameName, activity.backtest);
|
|
4721
4722
|
this._lookupMap.delete(key);
|
|
4722
4723
|
};
|
|
4723
4724
|
/**
|
|
@@ -12335,7 +12336,7 @@ const GET_RISK_FN = (dto, backtest, exchangeName, frameName, self) => {
|
|
|
12335
12336
|
* @param backtest - Whether running in backtest mode
|
|
12336
12337
|
* @returns Unique string key for memoization
|
|
12337
12338
|
*/
|
|
12338
|
-
const CREATE_KEY_FN$
|
|
12339
|
+
const CREATE_KEY_FN$A = (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
12339
12340
|
const parts = [symbol, strategyName, exchangeName];
|
|
12340
12341
|
if (frameName)
|
|
12341
12342
|
parts.push(frameName);
|
|
@@ -12356,6 +12357,7 @@ const CREATE_COMMIT_SCHEDULE_PING_FN = (self) => trycatch(async (symbol, strateg
|
|
|
12356
12357
|
symbol,
|
|
12357
12358
|
strategyName,
|
|
12358
12359
|
exchangeName,
|
|
12360
|
+
frameName: data.frameName,
|
|
12359
12361
|
currentPrice,
|
|
12360
12362
|
data,
|
|
12361
12363
|
backtest,
|
|
@@ -12423,6 +12425,7 @@ const CREATE_COMMIT_ACTIVE_PING_FN = (self) => trycatch(async (symbol, strategyN
|
|
|
12423
12425
|
symbol,
|
|
12424
12426
|
strategyName,
|
|
12425
12427
|
exchangeName,
|
|
12428
|
+
frameName: data.frameName,
|
|
12426
12429
|
currentPrice,
|
|
12427
12430
|
data,
|
|
12428
12431
|
backtest,
|
|
@@ -12635,7 +12638,7 @@ class StrategyConnectionService {
|
|
|
12635
12638
|
* @param backtest - Whether running in backtest mode
|
|
12636
12639
|
* @returns Configured ClientStrategy instance
|
|
12637
12640
|
*/
|
|
12638
|
-
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
12641
|
+
this.getStrategy = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$A(symbol, strategyName, exchangeName, frameName, backtest), (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
12639
12642
|
const { riskName = "", riskList = [], getSignal, interval = STRATEGY_DEFAULT_INTERVAL, callbacks, } = this.strategySchemaService.get(strategyName);
|
|
12640
12643
|
return new ClientStrategy({
|
|
12641
12644
|
symbol,
|
|
@@ -13597,7 +13600,7 @@ class StrategyConnectionService {
|
|
|
13597
13600
|
}
|
|
13598
13601
|
return;
|
|
13599
13602
|
}
|
|
13600
|
-
const key = CREATE_KEY_FN$
|
|
13603
|
+
const key = CREATE_KEY_FN$A(payload.symbol, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
13601
13604
|
if (!this.getStrategy.has(key)) {
|
|
13602
13605
|
return;
|
|
13603
13606
|
}
|
|
@@ -13995,11 +13998,51 @@ class StrategyConnectionService {
|
|
|
13995
13998
|
}
|
|
13996
13999
|
}
|
|
13997
14000
|
|
|
14001
|
+
const MS_PER_MINUTE$6 = 60000;
|
|
14002
|
+
const INTERVAL_MINUTES$7 = {
|
|
14003
|
+
"1m": 1,
|
|
14004
|
+
"3m": 3,
|
|
14005
|
+
"5m": 5,
|
|
14006
|
+
"15m": 15,
|
|
14007
|
+
"30m": 30,
|
|
14008
|
+
"1h": 60,
|
|
14009
|
+
"2h": 120,
|
|
14010
|
+
"4h": 240,
|
|
14011
|
+
"6h": 360,
|
|
14012
|
+
"8h": 480,
|
|
14013
|
+
"1d": 1440,
|
|
14014
|
+
};
|
|
14015
|
+
/**
|
|
14016
|
+
* Aligns timestamp down to the nearest interval boundary.
|
|
14017
|
+
* For example, for 15m interval: 00:17 -> 00:15, 00:44 -> 00:30
|
|
14018
|
+
*
|
|
14019
|
+
* Candle timestamp convention:
|
|
14020
|
+
* - Candle timestamp = openTime (when candle opens)
|
|
14021
|
+
* - Candle with timestamp 00:00 covers period [00:00, 00:15) for 15m interval
|
|
14022
|
+
*
|
|
14023
|
+
* Adapter contract:
|
|
14024
|
+
* - Adapter must return candles with timestamp = openTime
|
|
14025
|
+
* - First returned candle.timestamp must equal aligned since
|
|
14026
|
+
* - Adapter must return exactly `limit` candles
|
|
14027
|
+
*
|
|
14028
|
+
* @param date - Date to align
|
|
14029
|
+
* @param interval - Candle interval (e.g., "1m", "15m", "1h")
|
|
14030
|
+
* @returns New Date aligned down to interval boundary
|
|
14031
|
+
*/
|
|
14032
|
+
const alignToInterval = (date, interval) => {
|
|
14033
|
+
const minutes = INTERVAL_MINUTES$7[interval];
|
|
14034
|
+
if (minutes === undefined) {
|
|
14035
|
+
throw new Error(`alignToInterval: unknown interval=${interval}`);
|
|
14036
|
+
}
|
|
14037
|
+
const intervalMs = minutes * MS_PER_MINUTE$6;
|
|
14038
|
+
return new Date(Math.floor(date.getTime() / intervalMs) * intervalMs);
|
|
14039
|
+
};
|
|
14040
|
+
|
|
13998
14041
|
/**
|
|
13999
14042
|
* Maps FrameInterval to minutes for timestamp calculation.
|
|
14000
14043
|
* Used to generate timeframe arrays with proper spacing.
|
|
14001
14044
|
*/
|
|
14002
|
-
const INTERVAL_MINUTES$
|
|
14045
|
+
const INTERVAL_MINUTES$6 = {
|
|
14003
14046
|
"1m": 1,
|
|
14004
14047
|
"3m": 3,
|
|
14005
14048
|
"5m": 5,
|
|
@@ -14053,7 +14096,7 @@ const GET_TIMEFRAME_FN = async (symbol, self) => {
|
|
|
14053
14096
|
symbol,
|
|
14054
14097
|
});
|
|
14055
14098
|
const { interval, startDate, endDate } = self.params;
|
|
14056
|
-
const intervalMinutes = INTERVAL_MINUTES$
|
|
14099
|
+
const intervalMinutes = INTERVAL_MINUTES$6[interval];
|
|
14057
14100
|
if (!intervalMinutes) {
|
|
14058
14101
|
throw new Error(`ClientFrame unknown interval: ${interval}`);
|
|
14059
14102
|
}
|
|
@@ -14062,8 +14105,14 @@ const GET_TIMEFRAME_FN = async (symbol, self) => {
|
|
|
14062
14105
|
today.setUTCHours(0, 0, 0, 0);
|
|
14063
14106
|
// Ensure endDate doesn't go beyond today
|
|
14064
14107
|
const effectiveEndDate = endDate > today ? today : endDate;
|
|
14108
|
+
// Align the iteration start down to the 1-minute boundary so every generated
|
|
14109
|
+
// timestamp lands on a clean minute, matching live mode
|
|
14110
|
+
// (LiveLogicPrivateService aligns `when` via alignToInterval(new Date(), "1m")).
|
|
14111
|
+
// Without this, a startDate carrying sub-minute (or any non-aligned) offset
|
|
14112
|
+
// would propagate that offset to every tick `when` — and therefore to
|
|
14113
|
+
// IRuntimeInfo.when handed to Cron handlers — diverging from live behaviour.
|
|
14065
14114
|
const timeframes = [];
|
|
14066
|
-
let currentDate =
|
|
14115
|
+
let currentDate = alignToInterval(startDate, "1m");
|
|
14067
14116
|
while (currentDate <= effectiveEndDate) {
|
|
14068
14117
|
timeframes.push(new Date(currentDate));
|
|
14069
14118
|
currentDate = new Date(currentDate.getTime() + intervalMinutes * 60 * 1000);
|
|
@@ -14097,6 +14146,7 @@ class ClientFrame {
|
|
|
14097
14146
|
}
|
|
14098
14147
|
}
|
|
14099
14148
|
|
|
14149
|
+
const DEFAULT_INTERVAL = "1m";
|
|
14100
14150
|
/**
|
|
14101
14151
|
* Connection service routing frame operations to correct ClientFrame instance.
|
|
14102
14152
|
*
|
|
@@ -14140,7 +14190,7 @@ class FrameConnectionService {
|
|
|
14140
14190
|
logger: this.loggerService,
|
|
14141
14191
|
startDate,
|
|
14142
14192
|
endDate,
|
|
14143
|
-
interval,
|
|
14193
|
+
interval: interval || DEFAULT_INTERVAL,
|
|
14144
14194
|
callbacks,
|
|
14145
14195
|
});
|
|
14146
14196
|
});
|
|
@@ -14799,7 +14849,7 @@ class ClientRisk {
|
|
|
14799
14849
|
* @param backtest - Whether running in backtest mode
|
|
14800
14850
|
* @returns Unique string key for memoization
|
|
14801
14851
|
*/
|
|
14802
|
-
const CREATE_KEY_FN$
|
|
14852
|
+
const CREATE_KEY_FN$z = (riskName, exchangeName, frameName, backtest) => {
|
|
14803
14853
|
const parts = [riskName, exchangeName];
|
|
14804
14854
|
if (frameName)
|
|
14805
14855
|
parts.push(frameName);
|
|
@@ -14899,7 +14949,7 @@ class RiskConnectionService {
|
|
|
14899
14949
|
* @param backtest - True if backtest mode, false if live mode
|
|
14900
14950
|
* @returns Configured ClientRisk instance
|
|
14901
14951
|
*/
|
|
14902
|
-
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
14952
|
+
this.getRisk = memoize(([riskName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$z(riskName, exchangeName, frameName, backtest), (riskName, exchangeName, frameName, backtest) => {
|
|
14903
14953
|
const schema = this.riskSchemaService.get(riskName);
|
|
14904
14954
|
return new ClientRisk({
|
|
14905
14955
|
...schema,
|
|
@@ -14989,7 +15039,7 @@ class RiskConnectionService {
|
|
|
14989
15039
|
payload,
|
|
14990
15040
|
});
|
|
14991
15041
|
if (payload) {
|
|
14992
|
-
const key = CREATE_KEY_FN$
|
|
15042
|
+
const key = CREATE_KEY_FN$z(payload.riskName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
14993
15043
|
this.getRisk.clear(key);
|
|
14994
15044
|
}
|
|
14995
15045
|
else {
|
|
@@ -16108,7 +16158,7 @@ class ClientAction {
|
|
|
16108
16158
|
* @param backtest - Whether running in backtest mode
|
|
16109
16159
|
* @returns Unique string key for memoization
|
|
16110
16160
|
*/
|
|
16111
|
-
const CREATE_KEY_FN$
|
|
16161
|
+
const CREATE_KEY_FN$y = (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
16112
16162
|
const parts = [actionName, strategyName, exchangeName];
|
|
16113
16163
|
if (frameName)
|
|
16114
16164
|
parts.push(frameName);
|
|
@@ -16160,7 +16210,7 @@ class ActionConnectionService {
|
|
|
16160
16210
|
* @param backtest - True if backtest mode, false if live mode
|
|
16161
16211
|
* @returns Configured ClientAction instance
|
|
16162
16212
|
*/
|
|
16163
|
-
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$
|
|
16213
|
+
this.getAction = memoize(([actionName, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$y(actionName, strategyName, exchangeName, frameName, backtest), (actionName, strategyName, exchangeName, frameName, backtest) => {
|
|
16164
16214
|
const schema = this.actionSchemaService.get(actionName);
|
|
16165
16215
|
return new ClientAction({
|
|
16166
16216
|
...schema,
|
|
@@ -16386,7 +16436,7 @@ class ActionConnectionService {
|
|
|
16386
16436
|
await Promise.all(actions.map(async (action) => await action.dispose()));
|
|
16387
16437
|
return;
|
|
16388
16438
|
}
|
|
16389
|
-
const key = CREATE_KEY_FN$
|
|
16439
|
+
const key = CREATE_KEY_FN$y(payload.actionName, payload.strategyName, payload.exchangeName, payload.frameName, payload.backtest);
|
|
16390
16440
|
if (!this.getAction.has(key)) {
|
|
16391
16441
|
return;
|
|
16392
16442
|
}
|
|
@@ -16397,14 +16447,14 @@ class ActionConnectionService {
|
|
|
16397
16447
|
}
|
|
16398
16448
|
}
|
|
16399
16449
|
|
|
16400
|
-
const METHOD_NAME_VALIDATE$
|
|
16450
|
+
const METHOD_NAME_VALIDATE$6 = "exchangeCoreService validate";
|
|
16401
16451
|
/**
|
|
16402
16452
|
* Creates a unique key for memoizing validate calls.
|
|
16403
16453
|
* Key format: "exchangeName"
|
|
16404
16454
|
* @param exchangeName - Exchange name
|
|
16405
16455
|
* @returns Unique string key for memoization
|
|
16406
16456
|
*/
|
|
16407
|
-
const CREATE_KEY_FN$
|
|
16457
|
+
const CREATE_KEY_FN$x = (exchangeName) => {
|
|
16408
16458
|
return exchangeName;
|
|
16409
16459
|
};
|
|
16410
16460
|
/**
|
|
@@ -16428,11 +16478,11 @@ class ExchangeCoreService {
|
|
|
16428
16478
|
* @param exchangeName - Name of the exchange to validate
|
|
16429
16479
|
* @returns Promise that resolves when validation is complete
|
|
16430
16480
|
*/
|
|
16431
|
-
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$
|
|
16432
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
16481
|
+
this.validate = memoize(([exchangeName]) => CREATE_KEY_FN$x(exchangeName), async (exchangeName) => {
|
|
16482
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$6, {
|
|
16433
16483
|
exchangeName,
|
|
16434
16484
|
});
|
|
16435
|
-
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$
|
|
16485
|
+
this.exchangeValidationService.validate(exchangeName, METHOD_NAME_VALIDATE$6);
|
|
16436
16486
|
});
|
|
16437
16487
|
/**
|
|
16438
16488
|
* Fetches historical candles with execution context.
|
|
@@ -16701,14 +16751,14 @@ class ExchangeCoreService {
|
|
|
16701
16751
|
}
|
|
16702
16752
|
}
|
|
16703
16753
|
|
|
16704
|
-
const METHOD_NAME_VALIDATE$
|
|
16754
|
+
const METHOD_NAME_VALIDATE$5 = "strategyCoreService validate";
|
|
16705
16755
|
/**
|
|
16706
16756
|
* Creates a unique key for memoizing validate calls.
|
|
16707
16757
|
* Key format: "strategyName:exchangeName:frameName"
|
|
16708
16758
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
16709
16759
|
* @returns Unique string key for memoization
|
|
16710
16760
|
*/
|
|
16711
|
-
const CREATE_KEY_FN$
|
|
16761
|
+
const CREATE_KEY_FN$w = (context) => {
|
|
16712
16762
|
const parts = [context.strategyName, context.exchangeName];
|
|
16713
16763
|
if (context.frameName)
|
|
16714
16764
|
parts.push(context.frameName);
|
|
@@ -16731,6 +16781,7 @@ class StrategyCoreService {
|
|
|
16731
16781
|
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
16732
16782
|
this.exchangeValidationService = inject(TYPES.exchangeValidationService);
|
|
16733
16783
|
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
16784
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
16734
16785
|
/**
|
|
16735
16786
|
* Validates strategy and associated risk configuration.
|
|
16736
16787
|
*
|
|
@@ -16740,16 +16791,17 @@ class StrategyCoreService {
|
|
|
16740
16791
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
16741
16792
|
* @returns Promise that resolves when validation is complete
|
|
16742
16793
|
*/
|
|
16743
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
16744
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
16794
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$w(context), async (context) => {
|
|
16795
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$5, {
|
|
16745
16796
|
context,
|
|
16746
16797
|
});
|
|
16747
|
-
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
16748
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$
|
|
16749
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$
|
|
16750
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$
|
|
16751
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
16752
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
16798
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
16799
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$5);
|
|
16800
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$5);
|
|
16801
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$5);
|
|
16802
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$5);
|
|
16803
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$5));
|
|
16804
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$5));
|
|
16753
16805
|
});
|
|
16754
16806
|
/**
|
|
16755
16807
|
* Retrieves the currently active pending signal for the symbol.
|
|
@@ -18110,7 +18162,7 @@ class SizingGlobalService {
|
|
|
18110
18162
|
* @param context - Context with riskName, exchangeName, frameName
|
|
18111
18163
|
* @returns Unique string key for memoization
|
|
18112
18164
|
*/
|
|
18113
|
-
const CREATE_KEY_FN$
|
|
18165
|
+
const CREATE_KEY_FN$v = (context) => {
|
|
18114
18166
|
const parts = [context.riskName, context.exchangeName];
|
|
18115
18167
|
if (context.frameName)
|
|
18116
18168
|
parts.push(context.frameName);
|
|
@@ -18136,7 +18188,7 @@ class RiskGlobalService {
|
|
|
18136
18188
|
* @param payload - Payload with riskName, exchangeName and frameName
|
|
18137
18189
|
* @returns Promise that resolves when validation is complete
|
|
18138
18190
|
*/
|
|
18139
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
18191
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$v(context), async (context) => {
|
|
18140
18192
|
this.loggerService.log("riskGlobalService validate", {
|
|
18141
18193
|
context,
|
|
18142
18194
|
});
|
|
@@ -18228,14 +18280,14 @@ class RiskGlobalService {
|
|
|
18228
18280
|
}
|
|
18229
18281
|
}
|
|
18230
18282
|
|
|
18231
|
-
const METHOD_NAME_VALIDATE$
|
|
18283
|
+
const METHOD_NAME_VALIDATE$4 = "actionCoreService validate";
|
|
18232
18284
|
/**
|
|
18233
18285
|
* Creates a unique key for memoizing validate calls.
|
|
18234
18286
|
* Key format: "strategyName:exchangeName:frameName"
|
|
18235
18287
|
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
18236
18288
|
* @returns Unique string key for memoization
|
|
18237
18289
|
*/
|
|
18238
|
-
const CREATE_KEY_FN$
|
|
18290
|
+
const CREATE_KEY_FN$u = (context) => {
|
|
18239
18291
|
const parts = [context.strategyName, context.exchangeName];
|
|
18240
18292
|
if (context.frameName)
|
|
18241
18293
|
parts.push(context.frameName);
|
|
@@ -18279,17 +18331,17 @@ class ActionCoreService {
|
|
|
18279
18331
|
* @param context - Strategy execution context with strategyName, exchangeName and frameName
|
|
18280
18332
|
* @returns Promise that resolves when all validations complete
|
|
18281
18333
|
*/
|
|
18282
|
-
this.validate = memoize(([context]) => CREATE_KEY_FN$
|
|
18283
|
-
this.loggerService.log(METHOD_NAME_VALIDATE$
|
|
18334
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$u(context), async (context) => {
|
|
18335
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$4, {
|
|
18284
18336
|
context,
|
|
18285
18337
|
});
|
|
18286
18338
|
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
18287
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$
|
|
18288
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$
|
|
18289
|
-
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$
|
|
18290
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
18291
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$
|
|
18292
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$
|
|
18339
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE$4);
|
|
18340
|
+
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_VALIDATE$4);
|
|
18341
|
+
context.frameName && this.frameValidationService.validate(context.frameName, METHOD_NAME_VALIDATE$4);
|
|
18342
|
+
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$4);
|
|
18343
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE$4));
|
|
18344
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_VALIDATE$4));
|
|
18293
18345
|
});
|
|
18294
18346
|
/**
|
|
18295
18347
|
* Initializes all ClientAction instances for the strategy.
|
|
@@ -18785,8 +18837,8 @@ class FrameSchemaService {
|
|
|
18785
18837
|
if (typeof frameSchema.frameName !== "string") {
|
|
18786
18838
|
throw new Error(`frame schema validation failed: missing frameName`);
|
|
18787
18839
|
}
|
|
18788
|
-
if (typeof frameSchema.interval !== "string") {
|
|
18789
|
-
throw new Error(`frame schema validation failed:
|
|
18840
|
+
if (frameSchema.interval && typeof frameSchema.interval !== "string") {
|
|
18841
|
+
throw new Error(`frame schema validation failed: invalid interval for frameName=${frameSchema.frameName}`);
|
|
18790
18842
|
}
|
|
18791
18843
|
if (!(frameSchema.startDate instanceof Date)) {
|
|
18792
18844
|
throw new Error(`frame schema validation failed: missing startDate for frameName=${frameSchema.frameName}`);
|
|
@@ -19914,8 +19966,8 @@ class BacktestLogicPrivateService {
|
|
|
19914
19966
|
}
|
|
19915
19967
|
|
|
19916
19968
|
const EMITTER_CHECK_INTERVAL = 5000;
|
|
19917
|
-
const MS_PER_MINUTE$
|
|
19918
|
-
const INTERVAL_MINUTES$
|
|
19969
|
+
const MS_PER_MINUTE$5 = 60000;
|
|
19970
|
+
const INTERVAL_MINUTES$5 = {
|
|
19919
19971
|
"1m": 1,
|
|
19920
19972
|
"3m": 3,
|
|
19921
19973
|
"5m": 5,
|
|
@@ -19930,7 +19982,7 @@ const INTERVAL_MINUTES$6 = {
|
|
|
19930
19982
|
};
|
|
19931
19983
|
const createEmitter = memoize(([interval]) => `${interval}`, (interval) => {
|
|
19932
19984
|
const tickSubject = new Subject();
|
|
19933
|
-
const intervalMs = INTERVAL_MINUTES$
|
|
19985
|
+
const intervalMs = INTERVAL_MINUTES$5[interval] * MS_PER_MINUTE$5;
|
|
19934
19986
|
{
|
|
19935
19987
|
let lastAligned = Math.floor(Date.now() / intervalMs) * intervalMs;
|
|
19936
19988
|
Source.fromInterval(EMITTER_CHECK_INTERVAL)
|
|
@@ -19957,46 +20009,6 @@ const waitForCandle = async (interval) => {
|
|
|
19957
20009
|
return emitter.toPromise();
|
|
19958
20010
|
};
|
|
19959
20011
|
|
|
19960
|
-
const MS_PER_MINUTE$5 = 60000;
|
|
19961
|
-
const INTERVAL_MINUTES$5 = {
|
|
19962
|
-
"1m": 1,
|
|
19963
|
-
"3m": 3,
|
|
19964
|
-
"5m": 5,
|
|
19965
|
-
"15m": 15,
|
|
19966
|
-
"30m": 30,
|
|
19967
|
-
"1h": 60,
|
|
19968
|
-
"2h": 120,
|
|
19969
|
-
"4h": 240,
|
|
19970
|
-
"6h": 360,
|
|
19971
|
-
"8h": 480,
|
|
19972
|
-
"1d": 1440,
|
|
19973
|
-
};
|
|
19974
|
-
/**
|
|
19975
|
-
* Aligns timestamp down to the nearest interval boundary.
|
|
19976
|
-
* For example, for 15m interval: 00:17 -> 00:15, 00:44 -> 00:30
|
|
19977
|
-
*
|
|
19978
|
-
* Candle timestamp convention:
|
|
19979
|
-
* - Candle timestamp = openTime (when candle opens)
|
|
19980
|
-
* - Candle with timestamp 00:00 covers period [00:00, 00:15) for 15m interval
|
|
19981
|
-
*
|
|
19982
|
-
* Adapter contract:
|
|
19983
|
-
* - Adapter must return candles with timestamp = openTime
|
|
19984
|
-
* - First returned candle.timestamp must equal aligned since
|
|
19985
|
-
* - Adapter must return exactly `limit` candles
|
|
19986
|
-
*
|
|
19987
|
-
* @param date - Date to align
|
|
19988
|
-
* @param interval - Candle interval (e.g., "1m", "15m", "1h")
|
|
19989
|
-
* @returns New Date aligned down to interval boundary
|
|
19990
|
-
*/
|
|
19991
|
-
const alignToInterval = (date, interval) => {
|
|
19992
|
-
const minutes = INTERVAL_MINUTES$5[interval];
|
|
19993
|
-
if (minutes === undefined) {
|
|
19994
|
-
throw new Error(`alignToInterval: unknown interval=${interval}`);
|
|
19995
|
-
}
|
|
19996
|
-
const intervalMs = minutes * MS_PER_MINUTE$5;
|
|
19997
|
-
return new Date(Math.floor(date.getTime() / intervalMs) * intervalMs);
|
|
19998
|
-
};
|
|
19999
|
-
|
|
20000
20012
|
/**
|
|
20001
20013
|
* Private service for live trading orchestration using async generators.
|
|
20002
20014
|
*
|
|
@@ -20819,6 +20831,17 @@ class WalkerLogicPublicService {
|
|
|
20819
20831
|
}
|
|
20820
20832
|
|
|
20821
20833
|
const METHOD_NAME_RUN$2 = "liveCommandService run";
|
|
20834
|
+
const METHOD_NAME_VALIDATE$3 = "liveCommandService validate";
|
|
20835
|
+
/**
|
|
20836
|
+
* Creates a unique key for memoizing validate calls.
|
|
20837
|
+
* Key format: "strategyName:exchangeName:frameName"
|
|
20838
|
+
* @param context - Context with strategyName, exchangeName, frameName
|
|
20839
|
+
* @returns Unique string key for memoization
|
|
20840
|
+
*/
|
|
20841
|
+
const CREATE_KEY_FN$t = (context) => {
|
|
20842
|
+
const parts = [context.strategyName, context.exchangeName];
|
|
20843
|
+
return parts.join(":");
|
|
20844
|
+
};
|
|
20822
20845
|
/**
|
|
20823
20846
|
* Global service providing access to live trading functionality.
|
|
20824
20847
|
*
|
|
@@ -20834,6 +20857,25 @@ class LiveCommandService {
|
|
|
20834
20857
|
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
20835
20858
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
20836
20859
|
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
20860
|
+
/**
|
|
20861
|
+
* Validates strategy and associated risk configuration.
|
|
20862
|
+
* Memoized to avoid redundant validations for the same strategy-exchange combination.
|
|
20863
|
+
*
|
|
20864
|
+
* @param context - Context with strategyName, exchangeName
|
|
20865
|
+
* @param methodName - Name of the calling method for error tracking
|
|
20866
|
+
*/
|
|
20867
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$t(context), (context, methodName) => {
|
|
20868
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$3, {
|
|
20869
|
+
context,
|
|
20870
|
+
methodName,
|
|
20871
|
+
});
|
|
20872
|
+
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
20873
|
+
this.exchangeValidationService.validate(context.exchangeName, methodName);
|
|
20874
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
20875
|
+
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
20876
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
20877
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, methodName));
|
|
20878
|
+
});
|
|
20837
20879
|
/**
|
|
20838
20880
|
* Runs live trading for a symbol with context propagation.
|
|
20839
20881
|
*
|
|
@@ -20848,22 +20890,26 @@ class LiveCommandService {
|
|
|
20848
20890
|
symbol,
|
|
20849
20891
|
context,
|
|
20850
20892
|
});
|
|
20851
|
-
|
|
20852
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_RUN$2);
|
|
20853
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_RUN$2);
|
|
20854
|
-
}
|
|
20855
|
-
{
|
|
20856
|
-
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
20857
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_RUN$2);
|
|
20858
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_RUN$2));
|
|
20859
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_RUN$2));
|
|
20860
|
-
}
|
|
20893
|
+
this.validate(context, METHOD_NAME_RUN$2);
|
|
20861
20894
|
return this.liveLogicPublicService.run(symbol, context);
|
|
20862
20895
|
};
|
|
20863
20896
|
}
|
|
20864
20897
|
}
|
|
20865
20898
|
|
|
20866
20899
|
const METHOD_NAME_RUN$1 = "backtestCommandService run";
|
|
20900
|
+
const METHOD_NAME_VALIDATE$2 = "backtestCommandService validate";
|
|
20901
|
+
/**
|
|
20902
|
+
* Creates a unique key for memoizing validate calls.
|
|
20903
|
+
* Key format: "strategyName:exchangeName:frameName"
|
|
20904
|
+
* @param context - Context with strategyName, exchangeName, frameName
|
|
20905
|
+
* @returns Unique string key for memoization
|
|
20906
|
+
*/
|
|
20907
|
+
const CREATE_KEY_FN$s = (context) => {
|
|
20908
|
+
const parts = [context.strategyName, context.exchangeName];
|
|
20909
|
+
if (context.frameName)
|
|
20910
|
+
parts.push(context.frameName);
|
|
20911
|
+
return parts.join(":");
|
|
20912
|
+
};
|
|
20867
20913
|
/**
|
|
20868
20914
|
* Global service providing access to backtest functionality.
|
|
20869
20915
|
*
|
|
@@ -20880,6 +20926,26 @@ class BacktestCommandService {
|
|
|
20880
20926
|
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
20881
20927
|
this.exchangeValidationService = inject(TYPES.exchangeValidationService);
|
|
20882
20928
|
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
20929
|
+
/**
|
|
20930
|
+
* Validates strategy and associated risk configuration.
|
|
20931
|
+
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
20932
|
+
*
|
|
20933
|
+
* @param context - Context with strategyName, exchangeName and frameName
|
|
20934
|
+
* @param methodName - Name of the calling method for error tracking
|
|
20935
|
+
*/
|
|
20936
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$s(context), (context, methodName) => {
|
|
20937
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$2, {
|
|
20938
|
+
context,
|
|
20939
|
+
methodName,
|
|
20940
|
+
});
|
|
20941
|
+
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
20942
|
+
this.exchangeValidationService.validate(context.exchangeName, methodName);
|
|
20943
|
+
this.frameValidationService.validate(context.frameName, methodName);
|
|
20944
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
20945
|
+
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
20946
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
20947
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, methodName));
|
|
20948
|
+
});
|
|
20883
20949
|
/**
|
|
20884
20950
|
* Runs backtest for a symbol with context propagation.
|
|
20885
20951
|
*
|
|
@@ -20892,23 +20958,26 @@ class BacktestCommandService {
|
|
|
20892
20958
|
symbol,
|
|
20893
20959
|
context,
|
|
20894
20960
|
});
|
|
20895
|
-
|
|
20896
|
-
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_RUN$1);
|
|
20897
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_RUN$1);
|
|
20898
|
-
this.frameValidationService.validate(context.frameName, METHOD_NAME_RUN$1);
|
|
20899
|
-
}
|
|
20900
|
-
{
|
|
20901
|
-
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
20902
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_RUN$1);
|
|
20903
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_RUN$1));
|
|
20904
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_RUN$1));
|
|
20905
|
-
}
|
|
20961
|
+
this.validate(context, METHOD_NAME_RUN$1);
|
|
20906
20962
|
return this.backtestLogicPublicService.run(symbol, context);
|
|
20907
20963
|
};
|
|
20908
20964
|
}
|
|
20909
20965
|
}
|
|
20910
20966
|
|
|
20911
20967
|
const METHOD_NAME_RUN = "walkerCommandService run";
|
|
20968
|
+
const METHOD_NAME_VALIDATE$1 = "walkerCommandService validate";
|
|
20969
|
+
/**
|
|
20970
|
+
* Creates a unique key for memoizing validate calls.
|
|
20971
|
+
* Key format: "walkerName:exchangeName:frameName"
|
|
20972
|
+
* @param context - Context with walkerName, exchangeName, frameName
|
|
20973
|
+
* @returns Unique string key for memoization
|
|
20974
|
+
*/
|
|
20975
|
+
const CREATE_KEY_FN$r = (context) => {
|
|
20976
|
+
const parts = [context.walkerName, context.exchangeName];
|
|
20977
|
+
if (context.frameName)
|
|
20978
|
+
parts.push(context.frameName);
|
|
20979
|
+
return parts.join(":");
|
|
20980
|
+
};
|
|
20912
20981
|
/**
|
|
20913
20982
|
* Global service providing access to walker functionality.
|
|
20914
20983
|
*
|
|
@@ -20927,6 +20996,34 @@ class WalkerCommandService {
|
|
|
20927
20996
|
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
20928
20997
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
20929
20998
|
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
20999
|
+
/**
|
|
21000
|
+
* Validates walker and associated strategy configurations.
|
|
21001
|
+
* Memoized to avoid redundant validations for the same walker-exchange-frame combination.
|
|
21002
|
+
*
|
|
21003
|
+
* Strategy/risk/action validation is performed explicitly here in addition to the
|
|
21004
|
+
* cascade inside WalkerValidationService — this is critical-path code and the
|
|
21005
|
+
* redundant check is intentional defense-in-depth.
|
|
21006
|
+
*
|
|
21007
|
+
* @param context - Context with walkerName, exchangeName and frameName
|
|
21008
|
+
* @param methodName - Name of the calling method for error tracking
|
|
21009
|
+
*/
|
|
21010
|
+
this.validate = memoize(([context]) => CREATE_KEY_FN$r(context), (context, methodName) => {
|
|
21011
|
+
this.loggerService.log(METHOD_NAME_VALIDATE$1, {
|
|
21012
|
+
context,
|
|
21013
|
+
methodName,
|
|
21014
|
+
});
|
|
21015
|
+
this.exchangeValidationService.validate(context.exchangeName, methodName);
|
|
21016
|
+
this.frameValidationService.validate(context.frameName, methodName);
|
|
21017
|
+
this.walkerValidationService.validate(context.walkerName, methodName);
|
|
21018
|
+
const walkerSchema = this.walkerSchemaService.get(context.walkerName);
|
|
21019
|
+
for (const strategyName of walkerSchema.strategies) {
|
|
21020
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(strategyName);
|
|
21021
|
+
this.strategyValidationService.validate(strategyName, methodName);
|
|
21022
|
+
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
21023
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
21024
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, methodName));
|
|
21025
|
+
}
|
|
21026
|
+
});
|
|
20930
21027
|
/**
|
|
20931
21028
|
* Runs walker comparison for a symbol with context propagation.
|
|
20932
21029
|
*
|
|
@@ -20938,21 +21035,7 @@ class WalkerCommandService {
|
|
|
20938
21035
|
symbol,
|
|
20939
21036
|
context,
|
|
20940
21037
|
});
|
|
20941
|
-
|
|
20942
|
-
this.exchangeValidationService.validate(context.exchangeName, METHOD_NAME_RUN);
|
|
20943
|
-
this.frameValidationService.validate(context.frameName, METHOD_NAME_RUN);
|
|
20944
|
-
this.walkerValidationService.validate(context.walkerName, METHOD_NAME_RUN);
|
|
20945
|
-
}
|
|
20946
|
-
{
|
|
20947
|
-
const walkerSchema = this.walkerSchemaService.get(context.walkerName);
|
|
20948
|
-
for (const strategyName of walkerSchema.strategies) {
|
|
20949
|
-
const { riskName, riskList, actions } = this.strategySchemaService.get(strategyName);
|
|
20950
|
-
this.strategyValidationService.validate(strategyName, METHOD_NAME_RUN);
|
|
20951
|
-
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_RUN);
|
|
20952
|
-
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_RUN));
|
|
20953
|
-
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, METHOD_NAME_RUN));
|
|
20954
|
-
}
|
|
20955
|
-
}
|
|
21038
|
+
this.validate(context, METHOD_NAME_RUN);
|
|
20956
21039
|
return this.walkerLogicPublicService.run(symbol, context);
|
|
20957
21040
|
};
|
|
20958
21041
|
}
|
|
@@ -28675,6 +28758,36 @@ class WalkerValidationService {
|
|
|
28675
28758
|
* Injected logger service instance
|
|
28676
28759
|
*/
|
|
28677
28760
|
this.loggerService = inject(TYPES.loggerService);
|
|
28761
|
+
/**
|
|
28762
|
+
* @private
|
|
28763
|
+
* @readonly
|
|
28764
|
+
* Injected walker schema service instance
|
|
28765
|
+
*/
|
|
28766
|
+
this.walkerSchemaService = inject(TYPES.walkerSchemaService);
|
|
28767
|
+
/**
|
|
28768
|
+
* @private
|
|
28769
|
+
* @readonly
|
|
28770
|
+
* Injected strategy validation service instance
|
|
28771
|
+
*/
|
|
28772
|
+
this.strategyValidationService = inject(TYPES.strategyValidationService);
|
|
28773
|
+
/**
|
|
28774
|
+
* @private
|
|
28775
|
+
* @readonly
|
|
28776
|
+
* Injected strategy schema service instance
|
|
28777
|
+
*/
|
|
28778
|
+
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
28779
|
+
/**
|
|
28780
|
+
* @private
|
|
28781
|
+
* @readonly
|
|
28782
|
+
* Injected risk validation service instance
|
|
28783
|
+
*/
|
|
28784
|
+
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
28785
|
+
/**
|
|
28786
|
+
* @private
|
|
28787
|
+
* @readonly
|
|
28788
|
+
* Injected action validation service instance
|
|
28789
|
+
*/
|
|
28790
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
28678
28791
|
/**
|
|
28679
28792
|
* @private
|
|
28680
28793
|
* Map storing walker schemas by walker name
|
|
@@ -28696,9 +28809,12 @@ class WalkerValidationService {
|
|
|
28696
28809
|
this._walkerMap.set(walkerName, walkerSchema);
|
|
28697
28810
|
};
|
|
28698
28811
|
/**
|
|
28699
|
-
* Validates the existence of a walker
|
|
28812
|
+
* Validates the existence of a walker and its associated strategy configurations.
|
|
28813
|
+
* Each strategy referenced by the walker is validated via StrategyValidationService,
|
|
28814
|
+
* which in turn validates the strategy's risk profiles and actions.
|
|
28700
28815
|
* @public
|
|
28701
28816
|
* @throws {Error} If walkerName is not found
|
|
28817
|
+
* @throws {Error} If any referenced strategy (or its risk/actions) is invalid
|
|
28702
28818
|
* Memoized function to cache validation results
|
|
28703
28819
|
*/
|
|
28704
28820
|
this.validate = memoize(([walkerName]) => walkerName, (walkerName, source) => {
|
|
@@ -28710,6 +28826,14 @@ class WalkerValidationService {
|
|
|
28710
28826
|
if (!walker) {
|
|
28711
28827
|
throw new Error(`walker ${walkerName} not found source=${source}`);
|
|
28712
28828
|
}
|
|
28829
|
+
const walkerSchema = this.walkerSchemaService.get(walkerName);
|
|
28830
|
+
for (const strategyName of walkerSchema.strategies) {
|
|
28831
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(strategyName);
|
|
28832
|
+
this.strategyValidationService.validate(strategyName, source);
|
|
28833
|
+
riskName && this.riskValidationService.validate(riskName, source);
|
|
28834
|
+
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, source));
|
|
28835
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, source));
|
|
28836
|
+
}
|
|
28713
28837
|
return true;
|
|
28714
28838
|
});
|
|
28715
28839
|
/**
|
|
@@ -30146,6 +30270,10 @@ class PartialGlobalService {
|
|
|
30146
30270
|
* Frame validation service for validating frame existence.
|
|
30147
30271
|
*/
|
|
30148
30272
|
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
30273
|
+
/**
|
|
30274
|
+
* Action validation service for validating action existence.
|
|
30275
|
+
*/
|
|
30276
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
30149
30277
|
/**
|
|
30150
30278
|
* Validates strategy and associated risk configuration.
|
|
30151
30279
|
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
@@ -30161,9 +30289,10 @@ class PartialGlobalService {
|
|
|
30161
30289
|
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
30162
30290
|
this.exchangeValidationService.validate(context.exchangeName, methodName);
|
|
30163
30291
|
context.frameName && this.frameValidationService.validate(context.frameName, methodName);
|
|
30164
|
-
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
30292
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
30165
30293
|
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
30166
30294
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
30295
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, methodName));
|
|
30167
30296
|
});
|
|
30168
30297
|
/**
|
|
30169
30298
|
* Processes profit state and emits events for newly reached profit levels.
|
|
@@ -31230,6 +31359,10 @@ class BreakevenGlobalService {
|
|
|
31230
31359
|
* Frame validation service for validating frame existence.
|
|
31231
31360
|
*/
|
|
31232
31361
|
this.frameValidationService = inject(TYPES.frameValidationService);
|
|
31362
|
+
/**
|
|
31363
|
+
* Action validation service for validating frame existence.
|
|
31364
|
+
*/
|
|
31365
|
+
this.actionValidationService = inject(TYPES.actionValidationService);
|
|
31233
31366
|
/**
|
|
31234
31367
|
* Validates strategy and associated risk configuration.
|
|
31235
31368
|
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
@@ -31245,9 +31378,10 @@ class BreakevenGlobalService {
|
|
|
31245
31378
|
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
31246
31379
|
this.exchangeValidationService.validate(context.exchangeName, methodName);
|
|
31247
31380
|
context.frameName && this.frameValidationService.validate(context.frameName, methodName);
|
|
31248
|
-
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
31381
|
+
const { riskName, riskList, actions } = this.strategySchemaService.get(context.strategyName);
|
|
31249
31382
|
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
31250
31383
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
31384
|
+
actions && actions.forEach((actionName) => this.actionValidationService.validate(actionName, methodName));
|
|
31251
31385
|
});
|
|
31252
31386
|
/**
|
|
31253
31387
|
* Checks if breakeven should be triggered and emits event if conditions met.
|
|
@@ -36135,6 +36269,21 @@ class PriceMetaService {
|
|
|
36135
36269
|
* Instances are cached until clear() is called.
|
|
36136
36270
|
*/
|
|
36137
36271
|
this.getSource = memoize(([symbol, strategyName, exchangeName, frameName, backtest]) => CREATE_KEY_FN$b(symbol, strategyName, exchangeName, frameName, backtest), () => new BehaviorSubject());
|
|
36272
|
+
/**
|
|
36273
|
+
* Checks if a price exists for the given key and has emitted at least one value.
|
|
36274
|
+
*
|
|
36275
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
36276
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
36277
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
36278
|
+
* @returns True if a price exists and has emitted a value, false otherwise
|
|
36279
|
+
*/
|
|
36280
|
+
this.hasPrice = (symbol, context, backtest) => {
|
|
36281
|
+
const key = CREATE_KEY_FN$b(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
36282
|
+
if (!this.getSource.has(key)) {
|
|
36283
|
+
return false;
|
|
36284
|
+
}
|
|
36285
|
+
return !!this.getSource.get(key)?.data;
|
|
36286
|
+
};
|
|
36138
36287
|
/**
|
|
36139
36288
|
* Returns the current market price for the given symbol and context.
|
|
36140
36289
|
*
|
|
@@ -36797,6 +36946,129 @@ class NotificationHelperService {
|
|
|
36797
36946
|
}
|
|
36798
36947
|
}
|
|
36799
36948
|
|
|
36949
|
+
const GET_RANGE_FN = trycatch((self, context, backtest) => {
|
|
36950
|
+
if (!backtest) {
|
|
36951
|
+
return null;
|
|
36952
|
+
}
|
|
36953
|
+
const { startDate, endDate } = self.frameSchemaService.get(context.frameName);
|
|
36954
|
+
return {
|
|
36955
|
+
from: startDate,
|
|
36956
|
+
to: endDate,
|
|
36957
|
+
};
|
|
36958
|
+
}, {
|
|
36959
|
+
fallback: (error, self) => {
|
|
36960
|
+
const message = "RuntimeMetaService GET_RANGE_FN thrown";
|
|
36961
|
+
const payload = {
|
|
36962
|
+
error: errorData(error),
|
|
36963
|
+
message: getErrorMessage(error),
|
|
36964
|
+
};
|
|
36965
|
+
self.loggerService.warn(message, payload);
|
|
36966
|
+
console.error(message, payload);
|
|
36967
|
+
errorEmitter.next(error);
|
|
36968
|
+
},
|
|
36969
|
+
defaultValue: null,
|
|
36970
|
+
});
|
|
36971
|
+
const GET_INFO_FN = trycatch((self, context) => {
|
|
36972
|
+
const { info } = self.strategySchemaService.get(context.strategyName);
|
|
36973
|
+
return info || null;
|
|
36974
|
+
}, {
|
|
36975
|
+
fallback: (error, self) => {
|
|
36976
|
+
const message = "RuntimeMetaService GET_INFO_FN thrown";
|
|
36977
|
+
const payload = {
|
|
36978
|
+
error: errorData(error),
|
|
36979
|
+
message: getErrorMessage(error),
|
|
36980
|
+
};
|
|
36981
|
+
self.loggerService.warn(message, payload);
|
|
36982
|
+
console.error(message, payload);
|
|
36983
|
+
errorEmitter.next(error);
|
|
36984
|
+
},
|
|
36985
|
+
defaultValue: null,
|
|
36986
|
+
});
|
|
36987
|
+
const GET_PRICE_FN = trycatch(async (self, symbol, context, backtest) => {
|
|
36988
|
+
return await self.priceMetaService.getCurrentPrice(symbol, context, backtest);
|
|
36989
|
+
}, {
|
|
36990
|
+
fallback: (error, self) => {
|
|
36991
|
+
const message = "RuntimeMetaService GET_PRICE_FN thrown";
|
|
36992
|
+
const payload = {
|
|
36993
|
+
error: errorData(error),
|
|
36994
|
+
message: getErrorMessage(error),
|
|
36995
|
+
};
|
|
36996
|
+
self.loggerService.warn(message, payload);
|
|
36997
|
+
console.error(message, payload);
|
|
36998
|
+
errorEmitter.next(error);
|
|
36999
|
+
},
|
|
37000
|
+
defaultValue: null,
|
|
37001
|
+
});
|
|
37002
|
+
const RuntimeMetaService = singleton(class {
|
|
37003
|
+
constructor() {
|
|
37004
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
37005
|
+
this.timeMetaService = inject(TYPES.timeMetaService);
|
|
37006
|
+
this.priceMetaService = inject(TYPES.priceMetaService);
|
|
37007
|
+
this.frameSchemaService = inject(TYPES.frameSchemaService);
|
|
37008
|
+
this.strategySchemaService = inject(TYPES.strategySchemaService);
|
|
37009
|
+
/**
|
|
37010
|
+
* Fetches the time range for the current strategy execution context.
|
|
37011
|
+
*
|
|
37012
|
+
* For backtest mode, it retrieves the start and end dates from the frame schema.
|
|
37013
|
+
* For live mode, it returns null since there is no predefined time range.
|
|
37014
|
+
*
|
|
37015
|
+
* This method is memoized to optimize performance, as the time range for a given context will not change during execution.
|
|
37016
|
+
*
|
|
37017
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
37018
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
37019
|
+
* @returns An object containing 'from' and 'to' Date objects for backtest mode, or null for live mode
|
|
37020
|
+
*/
|
|
37021
|
+
this._getRange = memoize(([context, backtest]) => `${context.frameName}:${backtest ? "backtest" : "live"}`, (context, backtest) => {
|
|
37022
|
+
return GET_RANGE_FN(this, context, backtest);
|
|
37023
|
+
});
|
|
37024
|
+
/**
|
|
37025
|
+
* Fetches strategy-defined runtime information for the current execution context.
|
|
37026
|
+
*
|
|
37027
|
+
* This method retrieves the 'info' object defined in the strategy schema, which can contain any custom data the strategy wants to track at runtime.
|
|
37028
|
+
* The content of this object is not defined by the system and can be used freely by strategy implementations for monitoring, reporting, or external logic.
|
|
37029
|
+
*
|
|
37030
|
+
* This method is memoized to optimize performance, as the strategy info for a given context will not change during execution.
|
|
37031
|
+
*
|
|
37032
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
37033
|
+
* @returns The 'info' object defined in the strategy schema for the given strategy, or null if not defined
|
|
37034
|
+
*/
|
|
37035
|
+
this._getInfo = memoize(([context]) => context.strategyName, (context) => {
|
|
37036
|
+
return GET_INFO_FN(this, context);
|
|
37037
|
+
});
|
|
37038
|
+
/**
|
|
37039
|
+
* Fetches comprehensive runtime information for a given symbol and strategy context, including current price, timestamp, and strategy-specific info.
|
|
37040
|
+
*
|
|
37041
|
+
* This method aggregates data from multiple sources (time, price, frame schema, strategy schema) to provide a complete picture of the current runtime state for a strategy tick.
|
|
37042
|
+
*
|
|
37043
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
37044
|
+
* @param context - Strategy, exchange, and frame identifiers
|
|
37045
|
+
* @param backtest - True if backtest mode, false if live mode
|
|
37046
|
+
* @returns An object containing symbol, time range, strategy-defined info, context, timestamp, current price, and backtest flag
|
|
37047
|
+
*/
|
|
37048
|
+
this.getRuntimeInfo = async (symbol, context, backtest) => {
|
|
37049
|
+
this.loggerService.log("runtimeMetaService getRuntimeInfo", {
|
|
37050
|
+
symbol,
|
|
37051
|
+
context,
|
|
37052
|
+
backtest,
|
|
37053
|
+
});
|
|
37054
|
+
const timestamp = await this.timeMetaService.getTimestamp(symbol, context, backtest);
|
|
37055
|
+
const when = new Date(timestamp);
|
|
37056
|
+
const currentPrice = await GET_PRICE_FN(this, symbol, context, backtest);
|
|
37057
|
+
const range = this._getRange(context, backtest);
|
|
37058
|
+
const info = this._getInfo(context);
|
|
37059
|
+
return {
|
|
37060
|
+
symbol,
|
|
37061
|
+
range,
|
|
37062
|
+
info,
|
|
37063
|
+
context,
|
|
37064
|
+
backtest,
|
|
37065
|
+
when,
|
|
37066
|
+
currentPrice,
|
|
37067
|
+
};
|
|
37068
|
+
};
|
|
37069
|
+
}
|
|
37070
|
+
});
|
|
37071
|
+
|
|
36800
37072
|
{
|
|
36801
37073
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
36802
37074
|
}
|
|
@@ -36833,6 +37105,7 @@ class NotificationHelperService {
|
|
|
36833
37105
|
provide(TYPES.contextMetaService, () => new ContextMetaService());
|
|
36834
37106
|
provide(TYPES.priceMetaService, () => new PriceMetaService());
|
|
36835
37107
|
provide(TYPES.timeMetaService, () => new TimeMetaService());
|
|
37108
|
+
provide(TYPES.runtimeMetaService, () => new RuntimeMetaService());
|
|
36836
37109
|
}
|
|
36837
37110
|
{
|
|
36838
37111
|
provide(TYPES.sizingGlobalService, () => new SizingGlobalService());
|
|
@@ -36936,6 +37209,7 @@ const metaServices = {
|
|
|
36936
37209
|
timeMetaService: inject(TYPES.timeMetaService),
|
|
36937
37210
|
priceMetaService: inject(TYPES.priceMetaService),
|
|
36938
37211
|
contextMetaService: inject(TYPES.contextMetaService),
|
|
37212
|
+
runtimeMetaService: inject(TYPES.runtimeMetaService),
|
|
36939
37213
|
};
|
|
36940
37214
|
const globalServices = {
|
|
36941
37215
|
sizingGlobalService: inject(TYPES.sizingGlobalService),
|
|
@@ -50449,6 +50723,7 @@ const GET_TIMESTAMP_METHOD_NAME = "meta.getTimestamp";
|
|
|
50449
50723
|
const GET_MODE_METHOD_NAME = "meta.getMode";
|
|
50450
50724
|
const GET_SYMBOL_METHOD_NAME = "meta.getSymbol";
|
|
50451
50725
|
const GET_CONTEXT_METHOD_NAME = "meta.getContext";
|
|
50726
|
+
const GET_RUNTIME_INFO_METHOD_NAME = "meta.getRuntimeInfo";
|
|
50452
50727
|
/**
|
|
50453
50728
|
* Gets the current date from execution context.
|
|
50454
50729
|
*
|
|
@@ -50565,6 +50840,45 @@ async function getContext() {
|
|
|
50565
50840
|
}
|
|
50566
50841
|
return backtest.methodContextService.context;
|
|
50567
50842
|
}
|
|
50843
|
+
/**
|
|
50844
|
+
* Gets runtime information about the current execution environment.
|
|
50845
|
+
*
|
|
50846
|
+
* This includes details such as the current symbol, exchange, timeframe, strategy, and whether it's a backtest or live run.
|
|
50847
|
+
*
|
|
50848
|
+
* @returns Promise resolving to an object containing runtime information
|
|
50849
|
+
* @throws Error if method context or execution context is not active
|
|
50850
|
+
*
|
|
50851
|
+
* @example
|
|
50852
|
+
* ```typescript
|
|
50853
|
+
* const runtimeInfo = await getRuntimeInfo();
|
|
50854
|
+
* console.log(runtimeInfo);
|
|
50855
|
+
* // {
|
|
50856
|
+
* // symbol: "BTCUSDT",
|
|
50857
|
+
* // context: {,
|
|
50858
|
+
* // exchangeName: "Binance",
|
|
50859
|
+
* // frameName: "1m",
|
|
50860
|
+
* // strategyName: "MyStrategy",
|
|
50861
|
+
* // },
|
|
50862
|
+
* // backtest: false
|
|
50863
|
+
* // }
|
|
50864
|
+
* ```
|
|
50865
|
+
*/
|
|
50866
|
+
async function getRuntimeInfo() {
|
|
50867
|
+
backtest.loggerService.info(GET_RUNTIME_INFO_METHOD_NAME);
|
|
50868
|
+
if (!MethodContextService.hasContext()) {
|
|
50869
|
+
throw new Error("getRuntimeInfo requires a method context");
|
|
50870
|
+
}
|
|
50871
|
+
if (!ExecutionContextService.hasContext()) {
|
|
50872
|
+
throw new Error("getRuntimeInfo requires an execution context");
|
|
50873
|
+
}
|
|
50874
|
+
const { exchangeName, frameName, strategyName } = backtest.methodContextService.context;
|
|
50875
|
+
const { symbol, backtest: isBacktest } = backtest.executionContextService.context;
|
|
50876
|
+
return await backtest.runtimeMetaService.getRuntimeInfo(symbol, {
|
|
50877
|
+
exchangeName,
|
|
50878
|
+
frameName,
|
|
50879
|
+
strategyName,
|
|
50880
|
+
}, isBacktest);
|
|
50881
|
+
}
|
|
50568
50882
|
|
|
50569
50883
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_HANDLE_ACTIVE_PING = "RecentPersistBacktestUtils.handleActivePing";
|
|
50570
50884
|
const RECENT_PERSIST_BACKTEST_METHOD_NAME_GET_LATEST_SIGNAL = "RecentPersistBacktestUtils.getLatestSignal";
|
|
@@ -64591,6 +64905,20 @@ const CRON_METHOD_NAME_TICK = "CronUtils._tick";
|
|
|
64591
64905
|
const CRON_METHOD_NAME_ENABLE = "CronUtils.enable";
|
|
64592
64906
|
const CRON_METHOD_NAME_DISABLE = "CronUtils.disable";
|
|
64593
64907
|
const CRON_METHOD_NAME_DISPOSE = "CronUtils.dispose";
|
|
64908
|
+
/**
|
|
64909
|
+
* Watchdog timeout (ms) for a single cron handler invocation.
|
|
64910
|
+
*
|
|
64911
|
+
* A handler that does not settle within this window is treated as failed:
|
|
64912
|
+
* `_runEntry` races `entry.handler(info)` against this `sleep` and, when the
|
|
64913
|
+
* timeout wins, throws into the same `catch` as any other handler error —
|
|
64914
|
+
* surfacing `failed = true`, logging a warning, and (for periodic entries)
|
|
64915
|
+
* rolling back the watermark so the boundary is retried on the next tick.
|
|
64916
|
+
*
|
|
64917
|
+
* This guards the `singlerun`-serialised tick pipeline against a handler that
|
|
64918
|
+
* never resolves (a lost `resolve`, a hung promise with no timeout of its
|
|
64919
|
+
* own): without it such a handler would stall every subsequent tick forever.
|
|
64920
|
+
*/
|
|
64921
|
+
const CRON_HANDLER_TIMEOUT = 120000;
|
|
64594
64922
|
/**
|
|
64595
64923
|
* Local logger instance.
|
|
64596
64924
|
*
|
|
@@ -64599,6 +64927,20 @@ const CRON_METHOD_NAME_DISPOSE = "CronUtils.dispose";
|
|
|
64599
64927
|
* being bootstrapped — `Cron` can be imported and used in isolation.
|
|
64600
64928
|
*/
|
|
64601
64929
|
const LOGGER_SERVICE$1 = new LoggerService();
|
|
64930
|
+
/**
|
|
64931
|
+
* Local runtime-meta-service instance.
|
|
64932
|
+
*
|
|
64933
|
+
* Like {@link LOGGER_SERVICE}, instantiated directly via `new` rather than
|
|
64934
|
+
* resolved from the DI container so `CronUtils` carries no compile-time
|
|
64935
|
+
* dependency on a bootstrapped framework. `RuntimeMetaService` is built with
|
|
64936
|
+
* the `singleton` HOF from `di-singleton`, so `new RuntimeMetaService()`
|
|
64937
|
+
* returns the one shared singleton proxy — the same instance the rest of the
|
|
64938
|
+
* framework injects — and resolves its own dependencies lazily on first use.
|
|
64939
|
+
*
|
|
64940
|
+
* Used by {@link CronUtils._runEntry} to assemble the {@link IRuntimeInfo}
|
|
64941
|
+
* snapshot handed to each cron handler.
|
|
64942
|
+
*/
|
|
64943
|
+
const RUNTIME_META_SERVICE = new RuntimeMetaService();
|
|
64602
64944
|
/**
|
|
64603
64945
|
* Utility class for registering periodic tasks that fire on candle-interval
|
|
64604
64946
|
* boundaries of the virtual time produced by parallel backtests.
|
|
@@ -64621,8 +64963,8 @@ const LOGGER_SERVICE$1 = new LoggerService();
|
|
|
64621
64963
|
* Cron.register({
|
|
64622
64964
|
* name: "tg-signal-parser",
|
|
64623
64965
|
* interval: "1h",
|
|
64624
|
-
* handler: async (
|
|
64625
|
-
* await parseTelegramSignalsToMongo(when);
|
|
64966
|
+
* handler: async (info) => {
|
|
64967
|
+
* await parseTelegramSignalsToMongo(info.when);
|
|
64626
64968
|
* },
|
|
64627
64969
|
* });
|
|
64628
64970
|
*
|
|
@@ -64664,12 +65006,15 @@ class CronUtils {
|
|
|
64664
65006
|
* - Fire-once global: `${name}:once:g${generation}`.
|
|
64665
65007
|
* - Fire-once fan-out: `${name}:once:${symbol}:g${generation}`.
|
|
64666
65008
|
*
|
|
64667
|
-
* Value is the shared in-flight handler promise.
|
|
64668
|
-
*
|
|
64669
|
-
*
|
|
64670
|
-
*
|
|
64671
|
-
*
|
|
64672
|
-
*
|
|
65009
|
+
* Value is the shared in-flight handler promise. It resolves to a `boolean`
|
|
65010
|
+
* "failed" flag (`true` when the handler — or the runtime-info assembly —
|
|
65011
|
+
* threw), which `_tick` uses to roll back the periodic watermark of the slot
|
|
65012
|
+
* it opened so a failed boundary is retried. Every parallel `tick` for the
|
|
65013
|
+
* same slot key awaits this exact promise (mutex semantics) and is released
|
|
65014
|
+
* together when it settles. `_inFlight` is owned exclusively by `_runEntry` —
|
|
65015
|
+
* `clear()` does **not** touch it, so the singleshot promise survives
|
|
65016
|
+
* concurrent `clear` calls and continues to coordinate parallel ticks until
|
|
65017
|
+
* it settles.
|
|
64673
65018
|
*/
|
|
64674
65019
|
this._inFlight = new Map();
|
|
64675
65020
|
/**
|
|
@@ -64713,9 +65058,12 @@ class CronUtils {
|
|
|
64713
65058
|
*
|
|
64714
65059
|
* Written synchronously in `_tick` at slot-open time (before the `await`),
|
|
64715
65060
|
* so a still-in-flight handler does not let a later tick re-open the same
|
|
64716
|
-
* (or an already-passed) boundary.
|
|
64717
|
-
*
|
|
64718
|
-
*
|
|
65061
|
+
* (or an already-passed) boundary. If that handler then **fails**, the
|
|
65062
|
+
* advance is rolled back after the slot settles — the prior value is restored
|
|
65063
|
+
* (or the key deleted if there was none) — so the failed boundary is retried
|
|
65064
|
+
* on the next tick, mirroring catch-up of a skipped boundary. Fire-once
|
|
65065
|
+
* entries never touch this map — they use `_firedOnce`. Pruned by
|
|
65066
|
+
* `_clearBoundaryFor` on `register`/`unregister` and wiped by `dispose`.
|
|
64719
65067
|
*/
|
|
64720
65068
|
this._lastBoundary = new Map();
|
|
64721
65069
|
/**
|
|
@@ -64735,7 +65083,7 @@ class CronUtils {
|
|
|
64735
65083
|
* name: "fetch-funding",
|
|
64736
65084
|
* interval: "8h",
|
|
64737
65085
|
* symbols: ["BTCUSDT", "ETHUSDT"],
|
|
64738
|
-
* handler: async (
|
|
65086
|
+
* handler: async (info) => { ... },
|
|
64739
65087
|
* });
|
|
64740
65088
|
* // Later:
|
|
64741
65089
|
* dispose();
|
|
@@ -64855,7 +65203,7 @@ class CronUtils {
|
|
|
64855
65203
|
* 4. **Fire-once** (`entry.interval === undefined`):
|
|
64856
65204
|
* - If the entry's fired-once key is already in `_firedOnce`, skip.
|
|
64857
65205
|
* - Slot key: `${name}:once` (+ scope) (+ gen).
|
|
64858
|
-
* - `
|
|
65206
|
+
* - `alignedMs` = the 1-minute-aligned `when` from step 0 (`ts`).
|
|
64859
65207
|
* 5. **Periodic** (`entry.interval` set):
|
|
64860
65208
|
* - Align `when` to the entry's interval via {@link alignToInterval} to
|
|
64861
65209
|
* get `alignedMs`, the boundary this tick belongs to.
|
|
@@ -64877,32 +65225,44 @@ class CronUtils {
|
|
|
64877
65225
|
* handler is still in flight.
|
|
64878
65226
|
* - Slot key: `${name}:${alignedMs}` (+ scope) (+ gen).
|
|
64879
65227
|
* 6. Singleshot per slot key: look up the slot in `_inFlight`. If a promise
|
|
64880
|
-
* already exists, `await` the same promise. Otherwise
|
|
64881
|
-
*
|
|
64882
|
-
*
|
|
64883
|
-
*
|
|
64884
|
-
*
|
|
65228
|
+
* already exists, `await` the same promise. Otherwise open the slot via
|
|
65229
|
+
* {@link _runEntry} — which assembles the {@link IRuntimeInfo} snapshot
|
|
65230
|
+
* (from `symbol`, `context`, `backtest`) and invokes `entry.handler(info)`
|
|
65231
|
+
* — store the promise, and `await` it. The slot is removed in `.finally()`
|
|
65232
|
+
* so the next boundary creates a fresh promise; for fire-once entries the
|
|
65233
|
+
* fired-once key is also added to `_firedOnce` on success so subsequent
|
|
65234
|
+
* ticks skip it.
|
|
65235
|
+
* 7. After `await Promise.all`, roll back the watermark for every **periodic**
|
|
65236
|
+
* slot this tick *opened* (not the ones whose in-flight promise it reused)
|
|
65237
|
+
* whose handler reported failure, so the next tick re-opens and re-runs
|
|
65238
|
+
* that boundary.
|
|
64885
65239
|
*
|
|
64886
65240
|
* Errors thrown by `handler` are caught, logged via `console.error`, and
|
|
64887
65241
|
* **not** rethrown — a failing handler must not break the per-symbol
|
|
64888
65242
|
* tick loop or unblock other parallel backtests with an unhandled
|
|
64889
65243
|
* rejection. A failed fire-once handler is **not** marked as fired and
|
|
64890
|
-
* will retry on the next tick.
|
|
65244
|
+
* will retry on the next tick. A failed **periodic** handler likewise
|
|
65245
|
+
* retries: the boundary watermark advanced at slot-open time is rolled back
|
|
65246
|
+
* after the slot settles (step 7), so the next tick re-opens that boundary.
|
|
64891
65247
|
*
|
|
64892
65248
|
* Requires active method context and execution context.
|
|
64893
65249
|
*
|
|
64894
65250
|
* @param symbol - Trading symbol from the current tick.
|
|
64895
65251
|
* @param when - Virtual time of the current tick.
|
|
64896
65252
|
* @param backtest - `true` for backtest ticks, `false` for live ticks.
|
|
64897
|
-
* Forwarded
|
|
64898
|
-
* from the tick that **opens** a given slot is observed by all
|
|
64899
|
-
* awaiters of that slot.
|
|
65253
|
+
* Forwarded to {@link _runEntry} and surfaced as `info.backtest`. Only the
|
|
65254
|
+
* value from the tick that **opens** a given slot is observed by all
|
|
65255
|
+
* parallel awaiters of that slot.
|
|
65256
|
+
* @param context - Strategy/exchange/frame identifiers from the originating
|
|
65257
|
+
* lifecycle event, forwarded to `RuntimeMetaService.getRuntimeInfo` to
|
|
65258
|
+
* build the {@link IRuntimeInfo} snapshot passed to the handler.
|
|
64900
65259
|
* @throws Error if method or execution context is missing.
|
|
64901
65260
|
*/
|
|
64902
|
-
this._tick = async (symbol, when, backtest) => {
|
|
65261
|
+
this._tick = async (symbol, when, backtest, context) => {
|
|
64903
65262
|
LOGGER_SERVICE$1.debug(CRON_METHOD_NAME_TICK, {
|
|
64904
65263
|
symbol,
|
|
64905
65264
|
when,
|
|
65265
|
+
context,
|
|
64906
65266
|
});
|
|
64907
65267
|
if (!MethodContextService.hasContext()) {
|
|
64908
65268
|
throw new Error("CronUtils _tick requires method context");
|
|
@@ -64912,6 +65272,10 @@ class CronUtils {
|
|
|
64912
65272
|
}
|
|
64913
65273
|
const ts = alignToInterval(when, "1m").getTime();
|
|
64914
65274
|
const taskList = [];
|
|
65275
|
+
// Periodic slots THIS tick actually opened (the `!pending` branch), tracked
|
|
65276
|
+
// for watermark rollback on failure. See {@link IOpenedSlot} for what is and
|
|
65277
|
+
// is not recorded here and why.
|
|
65278
|
+
const openedList = [];
|
|
64915
65279
|
for (const { entry, generation } of this._entries.values()) {
|
|
64916
65280
|
if (entry.symbols?.length && !entry.symbols.includes(symbol)) {
|
|
64917
65281
|
continue;
|
|
@@ -64919,7 +65283,6 @@ class CronUtils {
|
|
|
64919
65283
|
const perSymbol = !!entry.symbols?.length;
|
|
64920
65284
|
const scope = perSymbol ? `:${symbol}` : "";
|
|
64921
65285
|
const genSuffix = `:g${generation}`;
|
|
64922
|
-
let aligned;
|
|
64923
65286
|
let alignedMs;
|
|
64924
65287
|
let slotKey;
|
|
64925
65288
|
let firedKey;
|
|
@@ -64931,15 +65294,13 @@ class CronUtils {
|
|
|
64931
65294
|
if (this._firedOnce.has(onceKey)) {
|
|
64932
65295
|
continue;
|
|
64933
65296
|
}
|
|
64934
|
-
aligned = alignToInterval(when, "1m");
|
|
64935
65297
|
alignedMs = ts;
|
|
64936
65298
|
slotKey = `${entry.name}:once${scope}${genSuffix}`;
|
|
64937
65299
|
firedKey = onceKey;
|
|
64938
65300
|
boundaryKey = null;
|
|
64939
65301
|
}
|
|
64940
65302
|
else {
|
|
64941
|
-
|
|
64942
|
-
alignedMs = aligned.getTime();
|
|
65303
|
+
alignedMs = alignToInterval(when, entry.interval).getTime();
|
|
64943
65304
|
boundaryKey = `${entry.name}${scope}${genSuffix}`;
|
|
64944
65305
|
const lastBoundary = this._lastBoundary.get(boundaryKey);
|
|
64945
65306
|
// Fire when the tick's aligned boundary has advanced past the last one
|
|
@@ -64957,16 +65318,70 @@ class CronUtils {
|
|
|
64957
65318
|
// Advance the watermark synchronously at slot-open time, before the
|
|
64958
65319
|
// await below. Otherwise a later tick on the same (or an already
|
|
64959
65320
|
// crossed) boundary, arriving while this handler is still in flight,
|
|
64960
|
-
// would see the stale watermark and open a duplicate slot.
|
|
65321
|
+
// would see the stale watermark and open a duplicate slot. The advance
|
|
65322
|
+
// is rolled back after the slot settles if the handler failed (see the
|
|
65323
|
+
// post-await loop below), so a failed boundary is retried next tick.
|
|
64961
65324
|
if (boundaryKey !== null) {
|
|
65325
|
+
// Capture the pre-advance value so it can be restored verbatim on
|
|
65326
|
+
// failure (undefined => the boundary had never opened => delete the
|
|
65327
|
+
// key on rollback). Read fresh here rather than reusing `lastBoundary`
|
|
65328
|
+
// above to keep the value↔slot binding local and obvious; there is no
|
|
65329
|
+
// `await` between the two reads, so they are identical.
|
|
65330
|
+
const prevBoundary = this._lastBoundary.get(boundaryKey);
|
|
64962
65331
|
this._lastBoundary.set(boundaryKey, alignedMs);
|
|
65332
|
+
pending = this._runEntry(entry, symbol, alignedMs, slotKey, firedKey, backtest, context);
|
|
65333
|
+
this._inFlight.set(slotKey, pending);
|
|
65334
|
+
openedList.push({ boundaryKey, prevBoundary, pending });
|
|
65335
|
+
}
|
|
65336
|
+
else {
|
|
65337
|
+
pending = this._runEntry(entry, symbol, alignedMs, slotKey, firedKey, backtest, context);
|
|
65338
|
+
this._inFlight.set(slotKey, pending);
|
|
64963
65339
|
}
|
|
64964
|
-
pending = this._runEntry(entry, symbol, aligned, alignedMs, slotKey, firedKey, backtest);
|
|
64965
|
-
this._inFlight.set(slotKey, pending);
|
|
64966
65340
|
}
|
|
64967
65341
|
taskList.push(pending);
|
|
64968
65342
|
}
|
|
64969
|
-
|
|
65343
|
+
{
|
|
65344
|
+
// Watchdog: warn (do not interrupt) if the slots this tick is awaiting
|
|
65345
|
+
// have not settled within CRON_HANDLER_TIMEOUT. We deliberately keep
|
|
65346
|
+
// awaiting Promise.all so the singlerun pipeline stays serialised and no
|
|
65347
|
+
// duplicate/zombie slots are spawned — the timer only surfaces the stall.
|
|
65348
|
+
// Use a real setTimeout/clearTimeout (not sleep) so the alarm is cancelled
|
|
65349
|
+
// the instant Promise.all resolves, rather than lingering for the full
|
|
65350
|
+
// timeout on every fast tick.
|
|
65351
|
+
const timer = setTimeout(() => {
|
|
65352
|
+
const message = `${CRON_METHOD_NAME_TICK} timed out after ${CRON_HANDLER_TIMEOUT}ms`;
|
|
65353
|
+
const payload = { symbol, when, context };
|
|
65354
|
+
LOGGER_SERVICE$1.warn(message, payload);
|
|
65355
|
+
console.error(message, payload);
|
|
65356
|
+
errorEmitter.next(new Error(message));
|
|
65357
|
+
}, CRON_HANDLER_TIMEOUT);
|
|
65358
|
+
try {
|
|
65359
|
+
await Promise.all(taskList);
|
|
65360
|
+
}
|
|
65361
|
+
finally {
|
|
65362
|
+
clearTimeout(timer);
|
|
65363
|
+
}
|
|
65364
|
+
}
|
|
65365
|
+
// Roll back the watermark for any periodic slot THIS tick opened whose
|
|
65366
|
+
// handler failed, so the next tick re-opens the same boundary and retries
|
|
65367
|
+
// it — mirroring how a skipped boundary is later caught up. Restoring
|
|
65368
|
+
// `prevBoundary` (or deleting the key when it was `undefined`) re-arms the
|
|
65369
|
+
// strict-`>` gate without disturbing any earlier already-fired boundary.
|
|
65370
|
+
// `await pending` is cheap — every promise already settled in `Promise.all`
|
|
65371
|
+
// above; we re-await via `openedList` because its entries (opened slots
|
|
65372
|
+
// only) do not line up with `taskList` indices.
|
|
65373
|
+
for (const { boundaryKey, prevBoundary, pending } of openedList) {
|
|
65374
|
+
const failed = await pending;
|
|
65375
|
+
if (!failed) {
|
|
65376
|
+
continue;
|
|
65377
|
+
}
|
|
65378
|
+
if (prevBoundary === undefined) {
|
|
65379
|
+
this._lastBoundary.delete(boundaryKey);
|
|
65380
|
+
}
|
|
65381
|
+
else {
|
|
65382
|
+
this._lastBoundary.set(boundaryKey, prevBoundary);
|
|
65383
|
+
}
|
|
65384
|
+
}
|
|
64970
65385
|
};
|
|
64971
65386
|
/**
|
|
64972
65387
|
* Subscribe `Cron` to the engine's strategy lifecycle subjects so registered
|
|
@@ -64981,7 +65396,11 @@ class CronUtils {
|
|
|
64981
65396
|
*
|
|
64982
65397
|
* All four subjects are subscribed to a single `singlerun`-wrapped
|
|
64983
65398
|
* handler that builds `_tick(event.symbol, new Date(event.timestamp),
|
|
64984
|
-
* event.backtest
|
|
65399
|
+
* event.backtest, { strategyName, exchangeName, frameName })`. The context
|
|
65400
|
+
* object is read uniformly from the event — every contract carries
|
|
65401
|
+
* `strategyName`, `exchangeName` and `frameName` at the top level (Active /
|
|
65402
|
+
* Schedule contracts gained `frameName` for exactly this reason), so no
|
|
65403
|
+
* per-event branching is needed. `singlerun` merges the four streams into one serial
|
|
64985
65404
|
* queue: at most one `_tick` runs at a time, the next waits. This matters
|
|
64986
65405
|
* because the engine can emit `beforeStart` and an immediate `idlePing`
|
|
64987
65406
|
* on the very same minute, and concurrent `_tick`s on the same
|
|
@@ -65017,7 +65436,11 @@ class CronUtils {
|
|
|
65017
65436
|
this.enable = singleshot(() => {
|
|
65018
65437
|
LOGGER_SERVICE$1.info(CRON_METHOD_NAME_ENABLE);
|
|
65019
65438
|
const handleTick = singlerun(async (event) => {
|
|
65020
|
-
return await this._tick(event.symbol, new Date(event.timestamp), event.backtest
|
|
65439
|
+
return await this._tick(event.symbol, new Date(event.timestamp), event.backtest, {
|
|
65440
|
+
strategyName: event.strategyName,
|
|
65441
|
+
exchangeName: event.exchangeName,
|
|
65442
|
+
frameName: event.frameName,
|
|
65443
|
+
});
|
|
65021
65444
|
});
|
|
65022
65445
|
const unBeforeStart = beforeStartSubject.subscribe(handleTick);
|
|
65023
65446
|
const unIdlePing = idlePingSubject.subscribe(handleTick);
|
|
@@ -65120,25 +65543,51 @@ class CronUtils {
|
|
|
65120
65543
|
/**
|
|
65121
65544
|
* Build the singleshot promise for a single in-flight slot.
|
|
65122
65545
|
*
|
|
65123
|
-
*
|
|
65124
|
-
*
|
|
65125
|
-
*
|
|
65126
|
-
*
|
|
65127
|
-
*
|
|
65128
|
-
*
|
|
65546
|
+
* Assembles the {@link IRuntimeInfo} snapshot via
|
|
65547
|
+
* `RuntimeMetaService.getRuntimeInfo(symbol, context, backtest)` and invokes
|
|
65548
|
+
* `entry.handler(info)`. Logs any error via `console.error` and **returns** a
|
|
65549
|
+
* `failed` boolean (`true` when the handler — or the runtime-info assembly —
|
|
65550
|
+
* threw) so the caller (`_tick`) can roll back the periodic watermark of the
|
|
65551
|
+
* slot it opened and retry that boundary. The error is **not** rethrown, so a
|
|
65552
|
+
* failing handler never produces an unhandled rejection. Clears the
|
|
65553
|
+
* `_inFlight` slot in `.finally()` so the next boundary produces a fresh
|
|
65554
|
+
* promise. For fire-once entries `firedKey` is added to `_firedOnce` on
|
|
65555
|
+
* success so subsequent ticks skip it.
|
|
65556
|
+
*
|
|
65557
|
+
* `getRuntimeInfo` is the user-facing aggregator: its sub-fetches (range,
|
|
65558
|
+
* info, price) are individually wrapped in `trycatch` with `null` fallbacks,
|
|
65559
|
+
* so it almost never throws for missing data. Whatever does throw — the
|
|
65560
|
+
* handler, or in rare cases `getRuntimeInfo` — is caught here and reported via
|
|
65561
|
+
* the returned `failed` flag; the watermark rollback treats both identically.
|
|
65562
|
+
*
|
|
65563
|
+
* @param context - Strategy/exchange/frame identifiers from the originating
|
|
65564
|
+
* lifecycle event, forwarded to `getRuntimeInfo` to resolve `range`/`info`.
|
|
65129
65565
|
* @param firedKey - Key to add to `_firedOnce` on success, or `null` for
|
|
65130
65566
|
* periodic entries (which never populate `_firedOnce`).
|
|
65131
|
-
* @param backtest -
|
|
65132
|
-
* "winner" tick's flag is what all parallel awaiters
|
|
65567
|
+
* @param backtest - Forwarded to `getRuntimeInfo` and surfaced as
|
|
65568
|
+
* `info.backtest`; the "winner" tick's flag is what all parallel awaiters
|
|
65569
|
+
* of this slot see.
|
|
65570
|
+
* @returns `true` if the handler (or `getRuntimeInfo`) threw, `false` on
|
|
65571
|
+
* success. `_tick` uses this to decide whether to roll back the watermark.
|
|
65133
65572
|
*/
|
|
65134
|
-
async _runEntry(entry, symbol,
|
|
65573
|
+
async _runEntry(entry, symbol, alignedMs, slotKey, firedKey, backtest, context) {
|
|
65135
65574
|
let failed = false;
|
|
65136
65575
|
try {
|
|
65137
|
-
await
|
|
65576
|
+
const info = await RUNTIME_META_SERVICE.getRuntimeInfo(symbol, context, backtest);
|
|
65577
|
+
await entry.handler(info);
|
|
65138
65578
|
}
|
|
65139
|
-
catch (
|
|
65579
|
+
catch (error) {
|
|
65140
65580
|
failed = true;
|
|
65141
|
-
|
|
65581
|
+
const message = `${CRON_METHOD_NAME_TICK} entry "${entry.name}" failed`;
|
|
65582
|
+
const payload = {
|
|
65583
|
+
symbol,
|
|
65584
|
+
alignedMs,
|
|
65585
|
+
error: errorData(error),
|
|
65586
|
+
message: getErrorMessage(error),
|
|
65587
|
+
};
|
|
65588
|
+
LOGGER_SERVICE$1.warn(message, payload);
|
|
65589
|
+
console.error(message, payload);
|
|
65590
|
+
errorEmitter.next(error);
|
|
65142
65591
|
}
|
|
65143
65592
|
finally {
|
|
65144
65593
|
this._inFlight.delete(slotKey);
|
|
@@ -65146,6 +65595,7 @@ class CronUtils {
|
|
|
65146
65595
|
this._firedOnce.add(firedKey);
|
|
65147
65596
|
}
|
|
65148
65597
|
}
|
|
65598
|
+
return failed;
|
|
65149
65599
|
}
|
|
65150
65600
|
}
|
|
65151
65601
|
/**
|
|
@@ -65159,7 +65609,7 @@ class CronUtils {
|
|
|
65159
65609
|
* Cron.register({
|
|
65160
65610
|
* name: "tg-parser",
|
|
65161
65611
|
* interval: "1h",
|
|
65162
|
-
* handler: async (
|
|
65612
|
+
* handler: async (info) => { ... },
|
|
65163
65613
|
* });
|
|
65164
65614
|
* ```
|
|
65165
65615
|
*/
|
|
@@ -66325,4 +66775,4 @@ const validateSignal = (signal, currentPrice) => {
|
|
|
66325
66775
|
return !errors.length;
|
|
66326
66776
|
};
|
|
66327
66777
|
|
|
66328
|
-
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Cron, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Lookup, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistBreakevenInstance, PersistCandleAdapter, PersistCandleInstance, PersistIntervalAdapter, PersistIntervalInstance, PersistLogAdapter, PersistLogInstance, PersistMeasureAdapter, PersistMeasureInstance, PersistMemoryAdapter, PersistMemoryInstance, PersistNotificationAdapter, PersistNotificationInstance, PersistPartialAdapter, PersistPartialInstance, PersistRecentAdapter, PersistRecentInstance, PersistRiskAdapter, PersistRiskInstance, PersistScheduleAdapter, PersistScheduleInstance, PersistSessionAdapter, PersistSessionInstance, PersistSignalAdapter, PersistSignalInstance, PersistStateAdapter, PersistStateInstance, PersistStorageAdapter, PersistStorageInstance, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, beginContext, beginTime, cacheCandles, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getClosePrice, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, intervalStepMs, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenAfterEnd, listenAfterEndOnce, listenBacktestProgress, listenBeforeStart, listenBeforeStartOnce, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toPlainString, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, waitForReady, warmCandles, writeMemory };
|
|
66778
|
+
export { ActionBase, Backtest, Breakeven, Broker, BrokerBase, Cache, Constant, Cron, Dump, Exchange, ExecutionContextService, Heat, HighestProfit, Interval, Live, Log, Lookup, Markdown, MarkdownFileBase, MarkdownFolderBase, MarkdownWriter, MaxDrawdown, Memory, MemoryBacktest, MemoryBacktestAdapter, MemoryLive, MemoryLiveAdapter, MethodContextService, Notification, NotificationBacktest, NotificationLive, Partial, Performance, PersistBase, PersistBreakevenAdapter, PersistBreakevenInstance, PersistCandleAdapter, PersistCandleInstance, PersistIntervalAdapter, PersistIntervalInstance, PersistLogAdapter, PersistLogInstance, PersistMeasureAdapter, PersistMeasureInstance, PersistMemoryAdapter, PersistMemoryInstance, PersistNotificationAdapter, PersistNotificationInstance, PersistPartialAdapter, PersistPartialInstance, PersistRecentAdapter, PersistRecentInstance, PersistRiskAdapter, PersistRiskInstance, PersistScheduleAdapter, PersistScheduleInstance, PersistSessionAdapter, PersistSessionInstance, PersistSignalAdapter, PersistSignalInstance, PersistStateAdapter, PersistStateInstance, PersistStorageAdapter, PersistStorageInstance, Position, PositionSize, Recent, RecentBacktest, RecentLive, Reflect$1 as Reflect, Report, ReportBase, ReportWriter, Risk, Schedule, Session, SessionBacktest, SessionLive, State, StateBacktest, StateBacktestAdapter, StateLive, StateLiveAdapter, Storage, StorageBacktest, StorageLive, Strategy, Sync, System, Walker, addActionSchema, addExchangeSchema, addFrameSchema, addRiskSchema, addSizingSchema, addStrategySchema, addWalkerSchema, alignToInterval, beginContext, beginTime, cacheCandles, checkCandles, commitActivateScheduled, commitAverageBuy, commitBreakeven, commitCancelScheduled, commitClosePending, commitPartialLoss, commitPartialLossCost, commitPartialProfit, commitPartialProfitCost, commitSignalNotify, commitTrailingStop, commitTrailingStopCost, commitTrailingTake, commitTrailingTakeCost, createSignalState, dumpAgentAnswer, dumpError, dumpJson, dumpRecord, dumpTable, dumpText, emitters, formatPrice, formatQuantity, get, getActionSchema, getAggregatedTrades, getAveragePrice, getBacktestTimeframe, getBreakeven, getCandles, getClosePrice, getColumns, getConfig, getContext, getDate, getDefaultColumns, getDefaultConfig, getEffectivePriceOpen, getExchangeSchema, getFrameSchema, getLatestSignal, getMaxDrawdownDistancePnlCost, getMaxDrawdownDistancePnlPercentage, getMinutesSinceLatestSignalCreated, getMode, getNextCandles, getOrderBook, getPendingSignal, getPositionActiveMinutes, getPositionCountdownMinutes, getPositionDrawdownMinutes, getPositionEffectivePrice, getPositionEntries, getPositionEntryOverlap, getPositionEstimateMinutes, getPositionHighestMaxDrawdownPnlCost, getPositionHighestMaxDrawdownPnlPercentage, getPositionHighestPnlCost, getPositionHighestPnlPercentage, getPositionHighestProfitBreakeven, getPositionHighestProfitDistancePnlCost, getPositionHighestProfitDistancePnlPercentage, getPositionHighestProfitMinutes, getPositionHighestProfitPrice, getPositionHighestProfitTimestamp, getPositionInvestedCost, getPositionInvestedCount, getPositionLevels, getPositionMaxDrawdownMinutes, getPositionMaxDrawdownPnlCost, getPositionMaxDrawdownPnlPercentage, getPositionMaxDrawdownPrice, getPositionMaxDrawdownTimestamp, getPositionPartialOverlap, getPositionPartials, getPositionPnlCost, getPositionPnlPercent, getPositionWaitingMinutes, getRawCandles, getRiskSchema, getRuntimeInfo, getScheduledSignal, getSessionData, getSignalState, getSizingSchema, getStrategySchema, getSymbol, getTimestamp, getTotalClosed, getTotalCostClosed, getTotalPercentClosed, getWalkerSchema, hasNoPendingSignal, hasNoScheduledSignal, hasTradeContext, intervalStepMs, investedCostToPercent, backtest as lib, listExchangeSchema, listFrameSchema, listMemory, listRiskSchema, listSizingSchema, listStrategySchema, listWalkerSchema, listenActivePing, listenActivePingOnce, listenAfterEnd, listenAfterEndOnce, listenBacktestProgress, listenBeforeStart, listenBeforeStartOnce, listenBreakevenAvailable, listenBreakevenAvailableOnce, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenHighestProfit, listenHighestProfitOnce, listenIdlePing, listenIdlePingOnce, listenMaxDrawdown, listenMaxDrawdownOnce, listenPartialLossAvailable, listenPartialLossAvailableOnce, listenPartialProfitAvailable, listenPartialProfitAvailableOnce, listenPerformance, listenRisk, listenRiskOnce, listenSchedulePing, listenSchedulePingOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalNotify, listenSignalNotifyOnce, listenSignalOnce, listenStrategyCommit, listenStrategyCommitOnce, listenSync, listenSyncOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, overrideActionSchema, overrideExchangeSchema, overrideFrameSchema, overrideRiskSchema, overrideSizingSchema, overrideStrategySchema, overrideWalkerSchema, parseArgs, percentDiff, percentToCloseCost, percentValue, readMemory, removeMemory, roundTicks, runInMockContext, searchMemory, set, setColumns, setConfig, setLogger, setSessionData, setSignalState, shutdown, slPercentShiftToPrice, slPriceToPercentShift, stopStrategy, toPlainString, toProfitLossDto, tpPercentShiftToPrice, tpPriceToPercentShift, validate, validateCommonSignal, validatePendingSignal, validateScheduledSignal, validateSignal, waitForCandle, waitForReady, warmCandles, writeMemory };
|