backtest-kit 1.7.1 → 1.7.2
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 +104 -69
- package/build/index.mjs +104 -69
- package/package.json +1 -1
- package/types.d.ts +48 -24
package/build/index.cjs
CHANGED
|
@@ -3402,7 +3402,7 @@ class ClientStrategy {
|
|
|
3402
3402
|
* // Existing signal will continue until natural close
|
|
3403
3403
|
* ```
|
|
3404
3404
|
*/
|
|
3405
|
-
async stop(symbol) {
|
|
3405
|
+
async stop(symbol, backtest) {
|
|
3406
3406
|
this.params.logger.debug("ClientStrategy stop", {
|
|
3407
3407
|
symbol,
|
|
3408
3408
|
hasPendingSignal: this._pendingSignal !== null,
|
|
@@ -3414,7 +3414,7 @@ class ClientStrategy {
|
|
|
3414
3414
|
return;
|
|
3415
3415
|
}
|
|
3416
3416
|
this._scheduledSignal = null;
|
|
3417
|
-
if (
|
|
3417
|
+
if (backtest) {
|
|
3418
3418
|
return;
|
|
3419
3419
|
}
|
|
3420
3420
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
@@ -3440,12 +3440,10 @@ class ClientStrategy {
|
|
|
3440
3440
|
* // Strategy continues, can generate new signals
|
|
3441
3441
|
* ```
|
|
3442
3442
|
*/
|
|
3443
|
-
async cancel(symbol, cancelId) {
|
|
3443
|
+
async cancel(symbol, backtest, cancelId) {
|
|
3444
3444
|
this.params.logger.debug("ClientStrategy cancel", {
|
|
3445
3445
|
symbol,
|
|
3446
|
-
strategyName: this.params.method.context.strategyName,
|
|
3447
3446
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3448
|
-
backtest: this.params.execution.context.backtest,
|
|
3449
3447
|
cancelId,
|
|
3450
3448
|
});
|
|
3451
3449
|
// Save cancelled signal for next tick to emit cancelled event
|
|
@@ -3455,7 +3453,7 @@ class ClientStrategy {
|
|
|
3455
3453
|
});
|
|
3456
3454
|
this._scheduledSignal = null;
|
|
3457
3455
|
}
|
|
3458
|
-
if (
|
|
3456
|
+
if (backtest) {
|
|
3459
3457
|
return;
|
|
3460
3458
|
}
|
|
3461
3459
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
@@ -4040,7 +4038,7 @@ class StrategyConnectionService {
|
|
|
4040
4038
|
context,
|
|
4041
4039
|
});
|
|
4042
4040
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4043
|
-
await strategy.stop(symbol);
|
|
4041
|
+
await strategy.stop(symbol, backtest);
|
|
4044
4042
|
};
|
|
4045
4043
|
/**
|
|
4046
4044
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -4084,7 +4082,7 @@ class StrategyConnectionService {
|
|
|
4084
4082
|
cancelId,
|
|
4085
4083
|
});
|
|
4086
4084
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4087
|
-
await strategy.cancel(symbol, cancelId);
|
|
4085
|
+
await strategy.cancel(symbol, backtest, cancelId);
|
|
4088
4086
|
};
|
|
4089
4087
|
}
|
|
4090
4088
|
}
|
|
@@ -5018,19 +5016,19 @@ class StrategyCoreService {
|
|
|
5018
5016
|
/**
|
|
5019
5017
|
* Validates strategy and associated risk configuration.
|
|
5020
5018
|
*
|
|
5021
|
-
* Memoized to avoid redundant validations for the same symbol-strategy
|
|
5019
|
+
* Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
|
|
5022
5020
|
* Logs validation activity.
|
|
5023
5021
|
* @param symbol - Trading pair symbol
|
|
5024
|
-
* @param
|
|
5022
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5025
5023
|
* @returns Promise that resolves when validation is complete
|
|
5026
5024
|
*/
|
|
5027
|
-
this.validate = functoolsKit.memoize(([symbol,
|
|
5025
|
+
this.validate = functoolsKit.memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
|
|
5028
5026
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
5029
5027
|
symbol,
|
|
5030
|
-
|
|
5028
|
+
context,
|
|
5031
5029
|
});
|
|
5032
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
5033
|
-
this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
|
|
5030
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
5031
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
5034
5032
|
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
5035
5033
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
5036
5034
|
});
|
|
@@ -5049,7 +5047,7 @@ class StrategyCoreService {
|
|
|
5049
5047
|
symbol,
|
|
5050
5048
|
context,
|
|
5051
5049
|
});
|
|
5052
|
-
await this.validate(symbol, context
|
|
5050
|
+
await this.validate(symbol, context);
|
|
5053
5051
|
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
|
|
5054
5052
|
};
|
|
5055
5053
|
/**
|
|
@@ -5067,7 +5065,7 @@ class StrategyCoreService {
|
|
|
5067
5065
|
symbol,
|
|
5068
5066
|
context,
|
|
5069
5067
|
});
|
|
5070
|
-
await this.validate(symbol, context
|
|
5068
|
+
await this.validate(symbol, context);
|
|
5071
5069
|
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
|
|
5072
5070
|
};
|
|
5073
5071
|
/**
|
|
@@ -5087,7 +5085,7 @@ class StrategyCoreService {
|
|
|
5087
5085
|
context,
|
|
5088
5086
|
backtest,
|
|
5089
5087
|
});
|
|
5090
|
-
await this.validate(symbol, context
|
|
5088
|
+
await this.validate(symbol, context);
|
|
5091
5089
|
return await this.strategyConnectionService.getStopped(backtest, symbol, context);
|
|
5092
5090
|
};
|
|
5093
5091
|
/**
|
|
@@ -5109,7 +5107,7 @@ class StrategyCoreService {
|
|
|
5109
5107
|
backtest,
|
|
5110
5108
|
context,
|
|
5111
5109
|
});
|
|
5112
|
-
await this.validate(symbol, context
|
|
5110
|
+
await this.validate(symbol, context);
|
|
5113
5111
|
return await ExecutionContextService.runInContext(async () => {
|
|
5114
5112
|
return await this.strategyConnectionService.tick(symbol, context);
|
|
5115
5113
|
}, {
|
|
@@ -5139,7 +5137,7 @@ class StrategyCoreService {
|
|
|
5139
5137
|
backtest,
|
|
5140
5138
|
context,
|
|
5141
5139
|
});
|
|
5142
|
-
await this.validate(symbol, context
|
|
5140
|
+
await this.validate(symbol, context);
|
|
5143
5141
|
return await ExecutionContextService.runInContext(async () => {
|
|
5144
5142
|
return await this.strategyConnectionService.backtest(symbol, context, candles);
|
|
5145
5143
|
}, {
|
|
@@ -5165,7 +5163,7 @@ class StrategyCoreService {
|
|
|
5165
5163
|
context,
|
|
5166
5164
|
backtest,
|
|
5167
5165
|
});
|
|
5168
|
-
await this.validate(symbol, context
|
|
5166
|
+
await this.validate(symbol, context);
|
|
5169
5167
|
return await this.strategyConnectionService.stop(backtest, symbol, context);
|
|
5170
5168
|
};
|
|
5171
5169
|
/**
|
|
@@ -5188,7 +5186,7 @@ class StrategyCoreService {
|
|
|
5188
5186
|
backtest,
|
|
5189
5187
|
cancelId,
|
|
5190
5188
|
});
|
|
5191
|
-
await this.validate(symbol, context
|
|
5189
|
+
await this.validate(symbol, context);
|
|
5192
5190
|
return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
|
|
5193
5191
|
};
|
|
5194
5192
|
/**
|
|
@@ -5204,7 +5202,11 @@ class StrategyCoreService {
|
|
|
5204
5202
|
payload,
|
|
5205
5203
|
});
|
|
5206
5204
|
if (payload) {
|
|
5207
|
-
await this.validate(payload.symbol,
|
|
5205
|
+
await this.validate(payload.symbol, {
|
|
5206
|
+
strategyName: payload.strategyName,
|
|
5207
|
+
exchangeName: payload.exchangeName,
|
|
5208
|
+
frameName: payload.frameName
|
|
5209
|
+
});
|
|
5208
5210
|
}
|
|
5209
5211
|
return await this.strategyConnectionService.clear(payload);
|
|
5210
5212
|
};
|
|
@@ -5287,16 +5289,16 @@ class RiskGlobalService {
|
|
|
5287
5289
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
5288
5290
|
/**
|
|
5289
5291
|
* Validates risk configuration.
|
|
5290
|
-
* Memoized to avoid redundant validations for the same risk
|
|
5292
|
+
* Memoized to avoid redundant validations for the same risk-exchange-frame combination.
|
|
5291
5293
|
* Logs validation activity.
|
|
5292
|
-
* @param
|
|
5294
|
+
* @param payload - Payload with riskName, exchangeName and frameName
|
|
5293
5295
|
* @returns Promise that resolves when validation is complete
|
|
5294
5296
|
*/
|
|
5295
|
-
this.validate = functoolsKit.memoize(([
|
|
5297
|
+
this.validate = functoolsKit.memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
|
|
5296
5298
|
this.loggerService.log("riskGlobalService validate", {
|
|
5297
|
-
|
|
5299
|
+
payload,
|
|
5298
5300
|
});
|
|
5299
|
-
this.riskValidationService.validate(riskName, "riskGlobalService validate");
|
|
5301
|
+
this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
|
|
5300
5302
|
});
|
|
5301
5303
|
/**
|
|
5302
5304
|
* Checks if a signal should be allowed based on risk limits.
|
|
@@ -5310,7 +5312,7 @@ class RiskGlobalService {
|
|
|
5310
5312
|
symbol: params.symbol,
|
|
5311
5313
|
payload,
|
|
5312
5314
|
});
|
|
5313
|
-
await this.validate(payload
|
|
5315
|
+
await this.validate(payload);
|
|
5314
5316
|
return await this.riskConnectionService.checkSignal(params, payload);
|
|
5315
5317
|
};
|
|
5316
5318
|
/**
|
|
@@ -5324,7 +5326,7 @@ class RiskGlobalService {
|
|
|
5324
5326
|
symbol,
|
|
5325
5327
|
payload,
|
|
5326
5328
|
});
|
|
5327
|
-
await this.validate(payload
|
|
5329
|
+
await this.validate(payload);
|
|
5328
5330
|
await this.riskConnectionService.addSignal(symbol, payload);
|
|
5329
5331
|
};
|
|
5330
5332
|
/**
|
|
@@ -5338,7 +5340,7 @@ class RiskGlobalService {
|
|
|
5338
5340
|
symbol,
|
|
5339
5341
|
payload,
|
|
5340
5342
|
});
|
|
5341
|
-
await this.validate(payload
|
|
5343
|
+
await this.validate(payload);
|
|
5342
5344
|
await this.riskConnectionService.removeSignal(symbol, payload);
|
|
5343
5345
|
};
|
|
5344
5346
|
/**
|
|
@@ -5352,7 +5354,7 @@ class RiskGlobalService {
|
|
|
5352
5354
|
payload,
|
|
5353
5355
|
});
|
|
5354
5356
|
if (payload) {
|
|
5355
|
-
await this.validate(payload
|
|
5357
|
+
await this.validate(payload);
|
|
5356
5358
|
}
|
|
5357
5359
|
return await this.riskConnectionService.clear(payload);
|
|
5358
5360
|
};
|
|
@@ -13370,18 +13372,18 @@ class PartialGlobalService {
|
|
|
13370
13372
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
13371
13373
|
/**
|
|
13372
13374
|
* Validates strategy and associated risk configuration.
|
|
13373
|
-
* Memoized to avoid redundant validations for the same strategy.
|
|
13375
|
+
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
13374
13376
|
*
|
|
13375
|
-
* @param
|
|
13377
|
+
* @param context - Context with strategyName, exchangeName and frameName
|
|
13376
13378
|
* @param methodName - Name of the calling method for error tracking
|
|
13377
13379
|
*/
|
|
13378
|
-
this.validate = functoolsKit.memoize(([
|
|
13380
|
+
this.validate = functoolsKit.memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
|
|
13379
13381
|
this.loggerService.log("partialGlobalService validate", {
|
|
13380
|
-
|
|
13382
|
+
context,
|
|
13381
13383
|
methodName,
|
|
13382
13384
|
});
|
|
13383
|
-
this.strategyValidationService.validate(strategyName, methodName);
|
|
13384
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
13385
|
+
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
13386
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
13385
13387
|
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
13386
13388
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
13387
13389
|
});
|
|
@@ -13407,7 +13409,11 @@ class PartialGlobalService {
|
|
|
13407
13409
|
backtest,
|
|
13408
13410
|
when,
|
|
13409
13411
|
});
|
|
13410
|
-
this.validate(
|
|
13412
|
+
this.validate({
|
|
13413
|
+
strategyName: data.strategyName,
|
|
13414
|
+
exchangeName: data.exchangeName,
|
|
13415
|
+
frameName: data.frameName
|
|
13416
|
+
}, "partialGlobalService profit");
|
|
13411
13417
|
return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
13412
13418
|
};
|
|
13413
13419
|
/**
|
|
@@ -13432,7 +13438,11 @@ class PartialGlobalService {
|
|
|
13432
13438
|
backtest,
|
|
13433
13439
|
when,
|
|
13434
13440
|
});
|
|
13435
|
-
this.validate(
|
|
13441
|
+
this.validate({
|
|
13442
|
+
strategyName: data.strategyName,
|
|
13443
|
+
exchangeName: data.exchangeName,
|
|
13444
|
+
frameName: data.frameName
|
|
13445
|
+
}, "partialGlobalService loss");
|
|
13436
13446
|
return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
13437
13447
|
};
|
|
13438
13448
|
/**
|
|
@@ -13452,7 +13462,11 @@ class PartialGlobalService {
|
|
|
13452
13462
|
priceClose,
|
|
13453
13463
|
backtest,
|
|
13454
13464
|
});
|
|
13455
|
-
this.validate(
|
|
13465
|
+
this.validate({
|
|
13466
|
+
strategyName: data.strategyName,
|
|
13467
|
+
exchangeName: data.exchangeName,
|
|
13468
|
+
frameName: data.frameName
|
|
13469
|
+
}, "partialGlobalService clear");
|
|
13456
13470
|
return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
|
|
13457
13471
|
};
|
|
13458
13472
|
}
|
|
@@ -18557,15 +18571,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
|
|
|
18557
18571
|
* import { Heat } from "backtest-kit";
|
|
18558
18572
|
*
|
|
18559
18573
|
* // Get raw heatmap data for a strategy
|
|
18560
|
-
* const stats = await Heat.getData(
|
|
18574
|
+
* const stats = await Heat.getData({
|
|
18575
|
+
* strategyName: "my-strategy",
|
|
18576
|
+
* exchangeName: "binance",
|
|
18577
|
+
* frameName: "frame1"
|
|
18578
|
+
* });
|
|
18561
18579
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18562
18580
|
*
|
|
18563
18581
|
* // Generate markdown report
|
|
18564
|
-
* const markdown = await Heat.getReport(
|
|
18582
|
+
* const markdown = await Heat.getReport({
|
|
18583
|
+
* strategyName: "my-strategy",
|
|
18584
|
+
* exchangeName: "binance",
|
|
18585
|
+
* frameName: "frame1"
|
|
18586
|
+
* });
|
|
18565
18587
|
* console.log(markdown);
|
|
18566
18588
|
*
|
|
18567
18589
|
* // Save to disk
|
|
18568
|
-
* await Heat.dump(
|
|
18590
|
+
* await Heat.dump({
|
|
18591
|
+
* strategyName: "my-strategy",
|
|
18592
|
+
* exchangeName: "binance",
|
|
18593
|
+
* frameName: "frame1"
|
|
18594
|
+
* }, false, "./reports");
|
|
18569
18595
|
* ```
|
|
18570
18596
|
*/
|
|
18571
18597
|
class HeatUtils {
|
|
@@ -18576,14 +18602,14 @@ class HeatUtils {
|
|
|
18576
18602
|
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
18577
18603
|
* Data is automatically collected from all closed signals for the strategy.
|
|
18578
18604
|
*
|
|
18579
|
-
* @param
|
|
18580
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18605
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18581
18606
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18582
18607
|
* @returns Promise resolving to heatmap statistics object
|
|
18583
18608
|
*
|
|
18584
18609
|
* @example
|
|
18585
18610
|
* ```typescript
|
|
18586
|
-
* const stats = await Heat.getData(
|
|
18611
|
+
* const stats = await Heat.getData({
|
|
18612
|
+
* strategyName: "my-strategy",
|
|
18587
18613
|
* exchangeName: "binance",
|
|
18588
18614
|
* frameName: "frame1"
|
|
18589
18615
|
* });
|
|
@@ -18598,11 +18624,11 @@ class HeatUtils {
|
|
|
18598
18624
|
* });
|
|
18599
18625
|
* ```
|
|
18600
18626
|
*/
|
|
18601
|
-
this.getData = async (
|
|
18602
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
|
|
18603
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18627
|
+
this.getData = async (context, backtest = false) => {
|
|
18628
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
|
|
18629
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18604
18630
|
{
|
|
18605
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18631
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18606
18632
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
|
|
18607
18633
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
|
|
18608
18634
|
}
|
|
@@ -18614,15 +18640,15 @@ class HeatUtils {
|
|
|
18614
18640
|
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
18615
18641
|
* Symbols are sorted by Total PNL descending.
|
|
18616
18642
|
*
|
|
18617
|
-
* @param
|
|
18618
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18643
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18619
18644
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18620
18645
|
* @param columns - Optional columns configuration for the report
|
|
18621
18646
|
* @returns Promise resolving to markdown formatted report string
|
|
18622
18647
|
*
|
|
18623
18648
|
* @example
|
|
18624
18649
|
* ```typescript
|
|
18625
|
-
* const markdown = await Heat.getReport(
|
|
18650
|
+
* const markdown = await Heat.getReport({
|
|
18651
|
+
* strategyName: "my-strategy",
|
|
18626
18652
|
* exchangeName: "binance",
|
|
18627
18653
|
* frameName: "frame1"
|
|
18628
18654
|
* });
|
|
@@ -18639,15 +18665,15 @@ class HeatUtils {
|
|
|
18639
18665
|
* // ...
|
|
18640
18666
|
* ```
|
|
18641
18667
|
*/
|
|
18642
|
-
this.getReport = async (
|
|
18643
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
|
|
18644
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18668
|
+
this.getReport = async (context, backtest = false, columns) => {
|
|
18669
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
|
|
18670
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18645
18671
|
{
|
|
18646
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18672
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18647
18673
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18648
18674
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
|
|
18649
18675
|
}
|
|
18650
|
-
return await backtest$1.heatMarkdownService.getReport(strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18676
|
+
return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18651
18677
|
};
|
|
18652
18678
|
/**
|
|
18653
18679
|
* Saves heatmap report to disk for a strategy.
|
|
@@ -18655,8 +18681,7 @@ class HeatUtils {
|
|
|
18655
18681
|
* Creates directory if it doesn't exist.
|
|
18656
18682
|
* Default filename: {strategyName}.md
|
|
18657
18683
|
*
|
|
18658
|
-
* @param
|
|
18659
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18684
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18660
18685
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18661
18686
|
* @param path - Optional directory path to save report (default: "./dump/heatmap")
|
|
18662
18687
|
* @param columns - Optional columns configuration for the report
|
|
@@ -18664,27 +18689,29 @@ class HeatUtils {
|
|
|
18664
18689
|
* @example
|
|
18665
18690
|
* ```typescript
|
|
18666
18691
|
* // Save to default path: ./dump/heatmap/my-strategy.md
|
|
18667
|
-
* await Heat.dump(
|
|
18692
|
+
* await Heat.dump({
|
|
18693
|
+
* strategyName: "my-strategy",
|
|
18668
18694
|
* exchangeName: "binance",
|
|
18669
18695
|
* frameName: "frame1"
|
|
18670
18696
|
* });
|
|
18671
18697
|
*
|
|
18672
18698
|
* // Save to custom path: ./reports/my-strategy.md
|
|
18673
|
-
* await Heat.dump(
|
|
18699
|
+
* await Heat.dump({
|
|
18700
|
+
* strategyName: "my-strategy",
|
|
18674
18701
|
* exchangeName: "binance",
|
|
18675
18702
|
* frameName: "frame1"
|
|
18676
18703
|
* }, false, "./reports");
|
|
18677
18704
|
* ```
|
|
18678
18705
|
*/
|
|
18679
|
-
this.dump = async (
|
|
18680
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
|
|
18681
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18706
|
+
this.dump = async (context, backtest = false, path, columns) => {
|
|
18707
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
|
|
18708
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18682
18709
|
{
|
|
18683
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18710
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18684
18711
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
|
|
18685
18712
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
|
|
18686
18713
|
}
|
|
18687
|
-
await backtest$1.heatMarkdownService.dump(strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18714
|
+
await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18688
18715
|
};
|
|
18689
18716
|
}
|
|
18690
18717
|
}
|
|
@@ -18696,7 +18723,11 @@ class HeatUtils {
|
|
|
18696
18723
|
* import { Heat } from "backtest-kit";
|
|
18697
18724
|
*
|
|
18698
18725
|
* // Strategy-specific heatmap
|
|
18699
|
-
* const stats = await Heat.getData(
|
|
18726
|
+
* const stats = await Heat.getData({
|
|
18727
|
+
* strategyName: "my-strategy",
|
|
18728
|
+
* exchangeName: "binance",
|
|
18729
|
+
* frameName: "frame1"
|
|
18730
|
+
* });
|
|
18700
18731
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18701
18732
|
* console.log(`Total Symbols: ${stats.totalSymbols}`);
|
|
18702
18733
|
*
|
|
@@ -18710,7 +18741,11 @@ class HeatUtils {
|
|
|
18710
18741
|
* });
|
|
18711
18742
|
*
|
|
18712
18743
|
* // Generate and save report
|
|
18713
|
-
* await Heat.dump(
|
|
18744
|
+
* await Heat.dump({
|
|
18745
|
+
* strategyName: "my-strategy",
|
|
18746
|
+
* exchangeName: "binance",
|
|
18747
|
+
* frameName: "frame1"
|
|
18748
|
+
* }, false, "./reports");
|
|
18714
18749
|
* ```
|
|
18715
18750
|
*/
|
|
18716
18751
|
const Heat = new HeatUtils();
|
package/build/index.mjs
CHANGED
|
@@ -3400,7 +3400,7 @@ class ClientStrategy {
|
|
|
3400
3400
|
* // Existing signal will continue until natural close
|
|
3401
3401
|
* ```
|
|
3402
3402
|
*/
|
|
3403
|
-
async stop(symbol) {
|
|
3403
|
+
async stop(symbol, backtest) {
|
|
3404
3404
|
this.params.logger.debug("ClientStrategy stop", {
|
|
3405
3405
|
symbol,
|
|
3406
3406
|
hasPendingSignal: this._pendingSignal !== null,
|
|
@@ -3412,7 +3412,7 @@ class ClientStrategy {
|
|
|
3412
3412
|
return;
|
|
3413
3413
|
}
|
|
3414
3414
|
this._scheduledSignal = null;
|
|
3415
|
-
if (
|
|
3415
|
+
if (backtest) {
|
|
3416
3416
|
return;
|
|
3417
3417
|
}
|
|
3418
3418
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
@@ -3438,12 +3438,10 @@ class ClientStrategy {
|
|
|
3438
3438
|
* // Strategy continues, can generate new signals
|
|
3439
3439
|
* ```
|
|
3440
3440
|
*/
|
|
3441
|
-
async cancel(symbol, cancelId) {
|
|
3441
|
+
async cancel(symbol, backtest, cancelId) {
|
|
3442
3442
|
this.params.logger.debug("ClientStrategy cancel", {
|
|
3443
3443
|
symbol,
|
|
3444
|
-
strategyName: this.params.method.context.strategyName,
|
|
3445
3444
|
hasScheduledSignal: this._scheduledSignal !== null,
|
|
3446
|
-
backtest: this.params.execution.context.backtest,
|
|
3447
3445
|
cancelId,
|
|
3448
3446
|
});
|
|
3449
3447
|
// Save cancelled signal for next tick to emit cancelled event
|
|
@@ -3453,7 +3451,7 @@ class ClientStrategy {
|
|
|
3453
3451
|
});
|
|
3454
3452
|
this._scheduledSignal = null;
|
|
3455
3453
|
}
|
|
3456
|
-
if (
|
|
3454
|
+
if (backtest) {
|
|
3457
3455
|
return;
|
|
3458
3456
|
}
|
|
3459
3457
|
await PersistScheduleAdapter.writeScheduleData(this._scheduledSignal, symbol, this.params.method.context.strategyName);
|
|
@@ -4038,7 +4036,7 @@ class StrategyConnectionService {
|
|
|
4038
4036
|
context,
|
|
4039
4037
|
});
|
|
4040
4038
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4041
|
-
await strategy.stop(symbol);
|
|
4039
|
+
await strategy.stop(symbol, backtest);
|
|
4042
4040
|
};
|
|
4043
4041
|
/**
|
|
4044
4042
|
* Clears the memoized ClientStrategy instance from cache.
|
|
@@ -4082,7 +4080,7 @@ class StrategyConnectionService {
|
|
|
4082
4080
|
cancelId,
|
|
4083
4081
|
});
|
|
4084
4082
|
const strategy = this.getStrategy(symbol, context.strategyName, context.exchangeName, context.frameName, backtest);
|
|
4085
|
-
await strategy.cancel(symbol, cancelId);
|
|
4083
|
+
await strategy.cancel(symbol, backtest, cancelId);
|
|
4086
4084
|
};
|
|
4087
4085
|
}
|
|
4088
4086
|
}
|
|
@@ -5016,19 +5014,19 @@ class StrategyCoreService {
|
|
|
5016
5014
|
/**
|
|
5017
5015
|
* Validates strategy and associated risk configuration.
|
|
5018
5016
|
*
|
|
5019
|
-
* Memoized to avoid redundant validations for the same symbol-strategy
|
|
5017
|
+
* Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
|
|
5020
5018
|
* Logs validation activity.
|
|
5021
5019
|
* @param symbol - Trading pair symbol
|
|
5022
|
-
* @param
|
|
5020
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
5023
5021
|
* @returns Promise that resolves when validation is complete
|
|
5024
5022
|
*/
|
|
5025
|
-
this.validate = memoize(([symbol,
|
|
5023
|
+
this.validate = memoize(([symbol, context]) => `${symbol}:${context.strategyName}:${context.exchangeName}:${context.frameName}`, async (symbol, context) => {
|
|
5026
5024
|
this.loggerService.log(METHOD_NAME_VALIDATE, {
|
|
5027
5025
|
symbol,
|
|
5028
|
-
|
|
5026
|
+
context,
|
|
5029
5027
|
});
|
|
5030
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
5031
|
-
this.strategyValidationService.validate(strategyName, METHOD_NAME_VALIDATE);
|
|
5028
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
5029
|
+
this.strategyValidationService.validate(context.strategyName, METHOD_NAME_VALIDATE);
|
|
5032
5030
|
riskName && this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE);
|
|
5033
5031
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, METHOD_NAME_VALIDATE));
|
|
5034
5032
|
});
|
|
@@ -5047,7 +5045,7 @@ class StrategyCoreService {
|
|
|
5047
5045
|
symbol,
|
|
5048
5046
|
context,
|
|
5049
5047
|
});
|
|
5050
|
-
await this.validate(symbol, context
|
|
5048
|
+
await this.validate(symbol, context);
|
|
5051
5049
|
return await this.strategyConnectionService.getPendingSignal(backtest, symbol, context);
|
|
5052
5050
|
};
|
|
5053
5051
|
/**
|
|
@@ -5065,7 +5063,7 @@ class StrategyCoreService {
|
|
|
5065
5063
|
symbol,
|
|
5066
5064
|
context,
|
|
5067
5065
|
});
|
|
5068
|
-
await this.validate(symbol, context
|
|
5066
|
+
await this.validate(symbol, context);
|
|
5069
5067
|
return await this.strategyConnectionService.getScheduledSignal(backtest, symbol, context);
|
|
5070
5068
|
};
|
|
5071
5069
|
/**
|
|
@@ -5085,7 +5083,7 @@ class StrategyCoreService {
|
|
|
5085
5083
|
context,
|
|
5086
5084
|
backtest,
|
|
5087
5085
|
});
|
|
5088
|
-
await this.validate(symbol, context
|
|
5086
|
+
await this.validate(symbol, context);
|
|
5089
5087
|
return await this.strategyConnectionService.getStopped(backtest, symbol, context);
|
|
5090
5088
|
};
|
|
5091
5089
|
/**
|
|
@@ -5107,7 +5105,7 @@ class StrategyCoreService {
|
|
|
5107
5105
|
backtest,
|
|
5108
5106
|
context,
|
|
5109
5107
|
});
|
|
5110
|
-
await this.validate(symbol, context
|
|
5108
|
+
await this.validate(symbol, context);
|
|
5111
5109
|
return await ExecutionContextService.runInContext(async () => {
|
|
5112
5110
|
return await this.strategyConnectionService.tick(symbol, context);
|
|
5113
5111
|
}, {
|
|
@@ -5137,7 +5135,7 @@ class StrategyCoreService {
|
|
|
5137
5135
|
backtest,
|
|
5138
5136
|
context,
|
|
5139
5137
|
});
|
|
5140
|
-
await this.validate(symbol, context
|
|
5138
|
+
await this.validate(symbol, context);
|
|
5141
5139
|
return await ExecutionContextService.runInContext(async () => {
|
|
5142
5140
|
return await this.strategyConnectionService.backtest(symbol, context, candles);
|
|
5143
5141
|
}, {
|
|
@@ -5163,7 +5161,7 @@ class StrategyCoreService {
|
|
|
5163
5161
|
context,
|
|
5164
5162
|
backtest,
|
|
5165
5163
|
});
|
|
5166
|
-
await this.validate(symbol, context
|
|
5164
|
+
await this.validate(symbol, context);
|
|
5167
5165
|
return await this.strategyConnectionService.stop(backtest, symbol, context);
|
|
5168
5166
|
};
|
|
5169
5167
|
/**
|
|
@@ -5186,7 +5184,7 @@ class StrategyCoreService {
|
|
|
5186
5184
|
backtest,
|
|
5187
5185
|
cancelId,
|
|
5188
5186
|
});
|
|
5189
|
-
await this.validate(symbol, context
|
|
5187
|
+
await this.validate(symbol, context);
|
|
5190
5188
|
return await this.strategyConnectionService.cancel(backtest, symbol, context, cancelId);
|
|
5191
5189
|
};
|
|
5192
5190
|
/**
|
|
@@ -5202,7 +5200,11 @@ class StrategyCoreService {
|
|
|
5202
5200
|
payload,
|
|
5203
5201
|
});
|
|
5204
5202
|
if (payload) {
|
|
5205
|
-
await this.validate(payload.symbol,
|
|
5203
|
+
await this.validate(payload.symbol, {
|
|
5204
|
+
strategyName: payload.strategyName,
|
|
5205
|
+
exchangeName: payload.exchangeName,
|
|
5206
|
+
frameName: payload.frameName
|
|
5207
|
+
});
|
|
5206
5208
|
}
|
|
5207
5209
|
return await this.strategyConnectionService.clear(payload);
|
|
5208
5210
|
};
|
|
@@ -5285,16 +5287,16 @@ class RiskGlobalService {
|
|
|
5285
5287
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
5286
5288
|
/**
|
|
5287
5289
|
* Validates risk configuration.
|
|
5288
|
-
* Memoized to avoid redundant validations for the same risk
|
|
5290
|
+
* Memoized to avoid redundant validations for the same risk-exchange-frame combination.
|
|
5289
5291
|
* Logs validation activity.
|
|
5290
|
-
* @param
|
|
5292
|
+
* @param payload - Payload with riskName, exchangeName and frameName
|
|
5291
5293
|
* @returns Promise that resolves when validation is complete
|
|
5292
5294
|
*/
|
|
5293
|
-
this.validate = memoize(([
|
|
5295
|
+
this.validate = memoize(([payload]) => `${payload.riskName}:${payload.exchangeName}:${payload.frameName}`, async (payload) => {
|
|
5294
5296
|
this.loggerService.log("riskGlobalService validate", {
|
|
5295
|
-
|
|
5297
|
+
payload,
|
|
5296
5298
|
});
|
|
5297
|
-
this.riskValidationService.validate(riskName, "riskGlobalService validate");
|
|
5299
|
+
this.riskValidationService.validate(payload.riskName, "riskGlobalService validate");
|
|
5298
5300
|
});
|
|
5299
5301
|
/**
|
|
5300
5302
|
* Checks if a signal should be allowed based on risk limits.
|
|
@@ -5308,7 +5310,7 @@ class RiskGlobalService {
|
|
|
5308
5310
|
symbol: params.symbol,
|
|
5309
5311
|
payload,
|
|
5310
5312
|
});
|
|
5311
|
-
await this.validate(payload
|
|
5313
|
+
await this.validate(payload);
|
|
5312
5314
|
return await this.riskConnectionService.checkSignal(params, payload);
|
|
5313
5315
|
};
|
|
5314
5316
|
/**
|
|
@@ -5322,7 +5324,7 @@ class RiskGlobalService {
|
|
|
5322
5324
|
symbol,
|
|
5323
5325
|
payload,
|
|
5324
5326
|
});
|
|
5325
|
-
await this.validate(payload
|
|
5327
|
+
await this.validate(payload);
|
|
5326
5328
|
await this.riskConnectionService.addSignal(symbol, payload);
|
|
5327
5329
|
};
|
|
5328
5330
|
/**
|
|
@@ -5336,7 +5338,7 @@ class RiskGlobalService {
|
|
|
5336
5338
|
symbol,
|
|
5337
5339
|
payload,
|
|
5338
5340
|
});
|
|
5339
|
-
await this.validate(payload
|
|
5341
|
+
await this.validate(payload);
|
|
5340
5342
|
await this.riskConnectionService.removeSignal(symbol, payload);
|
|
5341
5343
|
};
|
|
5342
5344
|
/**
|
|
@@ -5350,7 +5352,7 @@ class RiskGlobalService {
|
|
|
5350
5352
|
payload,
|
|
5351
5353
|
});
|
|
5352
5354
|
if (payload) {
|
|
5353
|
-
await this.validate(payload
|
|
5355
|
+
await this.validate(payload);
|
|
5354
5356
|
}
|
|
5355
5357
|
return await this.riskConnectionService.clear(payload);
|
|
5356
5358
|
};
|
|
@@ -13368,18 +13370,18 @@ class PartialGlobalService {
|
|
|
13368
13370
|
this.riskValidationService = inject(TYPES.riskValidationService);
|
|
13369
13371
|
/**
|
|
13370
13372
|
* Validates strategy and associated risk configuration.
|
|
13371
|
-
* Memoized to avoid redundant validations for the same strategy.
|
|
13373
|
+
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
13372
13374
|
*
|
|
13373
|
-
* @param
|
|
13375
|
+
* @param context - Context with strategyName, exchangeName and frameName
|
|
13374
13376
|
* @param methodName - Name of the calling method for error tracking
|
|
13375
13377
|
*/
|
|
13376
|
-
this.validate = memoize(([
|
|
13378
|
+
this.validate = memoize(([context]) => `${context.strategyName}:${context.exchangeName}:${context.frameName}`, (context, methodName) => {
|
|
13377
13379
|
this.loggerService.log("partialGlobalService validate", {
|
|
13378
|
-
|
|
13380
|
+
context,
|
|
13379
13381
|
methodName,
|
|
13380
13382
|
});
|
|
13381
|
-
this.strategyValidationService.validate(strategyName, methodName);
|
|
13382
|
-
const { riskName, riskList } = this.strategySchemaService.get(strategyName);
|
|
13383
|
+
this.strategyValidationService.validate(context.strategyName, methodName);
|
|
13384
|
+
const { riskName, riskList } = this.strategySchemaService.get(context.strategyName);
|
|
13383
13385
|
riskName && this.riskValidationService.validate(riskName, methodName);
|
|
13384
13386
|
riskList && riskList.forEach((riskName) => this.riskValidationService.validate(riskName, methodName));
|
|
13385
13387
|
});
|
|
@@ -13405,7 +13407,11 @@ class PartialGlobalService {
|
|
|
13405
13407
|
backtest,
|
|
13406
13408
|
when,
|
|
13407
13409
|
});
|
|
13408
|
-
this.validate(
|
|
13410
|
+
this.validate({
|
|
13411
|
+
strategyName: data.strategyName,
|
|
13412
|
+
exchangeName: data.exchangeName,
|
|
13413
|
+
frameName: data.frameName
|
|
13414
|
+
}, "partialGlobalService profit");
|
|
13409
13415
|
return await this.partialConnectionService.profit(symbol, data, currentPrice, revenuePercent, backtest, when);
|
|
13410
13416
|
};
|
|
13411
13417
|
/**
|
|
@@ -13430,7 +13436,11 @@ class PartialGlobalService {
|
|
|
13430
13436
|
backtest,
|
|
13431
13437
|
when,
|
|
13432
13438
|
});
|
|
13433
|
-
this.validate(
|
|
13439
|
+
this.validate({
|
|
13440
|
+
strategyName: data.strategyName,
|
|
13441
|
+
exchangeName: data.exchangeName,
|
|
13442
|
+
frameName: data.frameName
|
|
13443
|
+
}, "partialGlobalService loss");
|
|
13434
13444
|
return await this.partialConnectionService.loss(symbol, data, currentPrice, lossPercent, backtest, when);
|
|
13435
13445
|
};
|
|
13436
13446
|
/**
|
|
@@ -13450,7 +13460,11 @@ class PartialGlobalService {
|
|
|
13450
13460
|
priceClose,
|
|
13451
13461
|
backtest,
|
|
13452
13462
|
});
|
|
13453
|
-
this.validate(
|
|
13463
|
+
this.validate({
|
|
13464
|
+
strategyName: data.strategyName,
|
|
13465
|
+
exchangeName: data.exchangeName,
|
|
13466
|
+
frameName: data.frameName
|
|
13467
|
+
}, "partialGlobalService clear");
|
|
13454
13468
|
return await this.partialConnectionService.clear(symbol, data, priceClose, backtest);
|
|
13455
13469
|
};
|
|
13456
13470
|
}
|
|
@@ -18555,15 +18569,27 @@ const HEAT_METHOD_NAME_DUMP = "HeatUtils.dump";
|
|
|
18555
18569
|
* import { Heat } from "backtest-kit";
|
|
18556
18570
|
*
|
|
18557
18571
|
* // Get raw heatmap data for a strategy
|
|
18558
|
-
* const stats = await Heat.getData(
|
|
18572
|
+
* const stats = await Heat.getData({
|
|
18573
|
+
* strategyName: "my-strategy",
|
|
18574
|
+
* exchangeName: "binance",
|
|
18575
|
+
* frameName: "frame1"
|
|
18576
|
+
* });
|
|
18559
18577
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18560
18578
|
*
|
|
18561
18579
|
* // Generate markdown report
|
|
18562
|
-
* const markdown = await Heat.getReport(
|
|
18580
|
+
* const markdown = await Heat.getReport({
|
|
18581
|
+
* strategyName: "my-strategy",
|
|
18582
|
+
* exchangeName: "binance",
|
|
18583
|
+
* frameName: "frame1"
|
|
18584
|
+
* });
|
|
18563
18585
|
* console.log(markdown);
|
|
18564
18586
|
*
|
|
18565
18587
|
* // Save to disk
|
|
18566
|
-
* await Heat.dump(
|
|
18588
|
+
* await Heat.dump({
|
|
18589
|
+
* strategyName: "my-strategy",
|
|
18590
|
+
* exchangeName: "binance",
|
|
18591
|
+
* frameName: "frame1"
|
|
18592
|
+
* }, false, "./reports");
|
|
18567
18593
|
* ```
|
|
18568
18594
|
*/
|
|
18569
18595
|
class HeatUtils {
|
|
@@ -18574,14 +18600,14 @@ class HeatUtils {
|
|
|
18574
18600
|
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
18575
18601
|
* Data is automatically collected from all closed signals for the strategy.
|
|
18576
18602
|
*
|
|
18577
|
-
* @param
|
|
18578
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18603
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18579
18604
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18580
18605
|
* @returns Promise resolving to heatmap statistics object
|
|
18581
18606
|
*
|
|
18582
18607
|
* @example
|
|
18583
18608
|
* ```typescript
|
|
18584
|
-
* const stats = await Heat.getData(
|
|
18609
|
+
* const stats = await Heat.getData({
|
|
18610
|
+
* strategyName: "my-strategy",
|
|
18585
18611
|
* exchangeName: "binance",
|
|
18586
18612
|
* frameName: "frame1"
|
|
18587
18613
|
* });
|
|
@@ -18596,11 +18622,11 @@ class HeatUtils {
|
|
|
18596
18622
|
* });
|
|
18597
18623
|
* ```
|
|
18598
18624
|
*/
|
|
18599
|
-
this.getData = async (
|
|
18600
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName });
|
|
18601
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18625
|
+
this.getData = async (context, backtest = false) => {
|
|
18626
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_DATA, { strategyName: context.strategyName });
|
|
18627
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_DATA);
|
|
18602
18628
|
{
|
|
18603
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18629
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18604
18630
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA);
|
|
18605
18631
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_DATA));
|
|
18606
18632
|
}
|
|
@@ -18612,15 +18638,15 @@ class HeatUtils {
|
|
|
18612
18638
|
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
18613
18639
|
* Symbols are sorted by Total PNL descending.
|
|
18614
18640
|
*
|
|
18615
|
-
* @param
|
|
18616
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18641
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18617
18642
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18618
18643
|
* @param columns - Optional columns configuration for the report
|
|
18619
18644
|
* @returns Promise resolving to markdown formatted report string
|
|
18620
18645
|
*
|
|
18621
18646
|
* @example
|
|
18622
18647
|
* ```typescript
|
|
18623
|
-
* const markdown = await Heat.getReport(
|
|
18648
|
+
* const markdown = await Heat.getReport({
|
|
18649
|
+
* strategyName: "my-strategy",
|
|
18624
18650
|
* exchangeName: "binance",
|
|
18625
18651
|
* frameName: "frame1"
|
|
18626
18652
|
* });
|
|
@@ -18637,15 +18663,15 @@ class HeatUtils {
|
|
|
18637
18663
|
* // ...
|
|
18638
18664
|
* ```
|
|
18639
18665
|
*/
|
|
18640
|
-
this.getReport = async (
|
|
18641
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName });
|
|
18642
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18666
|
+
this.getReport = async (context, backtest = false, columns) => {
|
|
18667
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_GET_REPORT, { strategyName: context.strategyName });
|
|
18668
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18643
18669
|
{
|
|
18644
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18670
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18645
18671
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT);
|
|
18646
18672
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_GET_REPORT));
|
|
18647
18673
|
}
|
|
18648
|
-
return await backtest$1.heatMarkdownService.getReport(strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18674
|
+
return await backtest$1.heatMarkdownService.getReport(context.strategyName, context.exchangeName, context.frameName, backtest, columns);
|
|
18649
18675
|
};
|
|
18650
18676
|
/**
|
|
18651
18677
|
* Saves heatmap report to disk for a strategy.
|
|
@@ -18653,8 +18679,7 @@ class HeatUtils {
|
|
|
18653
18679
|
* Creates directory if it doesn't exist.
|
|
18654
18680
|
* Default filename: {strategyName}.md
|
|
18655
18681
|
*
|
|
18656
|
-
* @param
|
|
18657
|
-
* @param context - Execution context with exchangeName and frameName
|
|
18682
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
18658
18683
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
18659
18684
|
* @param path - Optional directory path to save report (default: "./dump/heatmap")
|
|
18660
18685
|
* @param columns - Optional columns configuration for the report
|
|
@@ -18662,27 +18687,29 @@ class HeatUtils {
|
|
|
18662
18687
|
* @example
|
|
18663
18688
|
* ```typescript
|
|
18664
18689
|
* // Save to default path: ./dump/heatmap/my-strategy.md
|
|
18665
|
-
* await Heat.dump(
|
|
18690
|
+
* await Heat.dump({
|
|
18691
|
+
* strategyName: "my-strategy",
|
|
18666
18692
|
* exchangeName: "binance",
|
|
18667
18693
|
* frameName: "frame1"
|
|
18668
18694
|
* });
|
|
18669
18695
|
*
|
|
18670
18696
|
* // Save to custom path: ./reports/my-strategy.md
|
|
18671
|
-
* await Heat.dump(
|
|
18697
|
+
* await Heat.dump({
|
|
18698
|
+
* strategyName: "my-strategy",
|
|
18672
18699
|
* exchangeName: "binance",
|
|
18673
18700
|
* frameName: "frame1"
|
|
18674
18701
|
* }, false, "./reports");
|
|
18675
18702
|
* ```
|
|
18676
18703
|
*/
|
|
18677
|
-
this.dump = async (
|
|
18678
|
-
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName, path });
|
|
18679
|
-
backtest$1.strategyValidationService.validate(strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18704
|
+
this.dump = async (context, backtest = false, path, columns) => {
|
|
18705
|
+
backtest$1.loggerService.info(HEAT_METHOD_NAME_DUMP, { strategyName: context.strategyName, path });
|
|
18706
|
+
backtest$1.strategyValidationService.validate(context.strategyName, HEAT_METHOD_NAME_DUMP);
|
|
18680
18707
|
{
|
|
18681
|
-
const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
|
|
18708
|
+
const { riskName, riskList } = backtest$1.strategySchemaService.get(context.strategyName);
|
|
18682
18709
|
riskName && backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP);
|
|
18683
18710
|
riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, HEAT_METHOD_NAME_DUMP));
|
|
18684
18711
|
}
|
|
18685
|
-
await backtest$1.heatMarkdownService.dump(strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18712
|
+
await backtest$1.heatMarkdownService.dump(context.strategyName, context.exchangeName, context.frameName, backtest, path, columns);
|
|
18686
18713
|
};
|
|
18687
18714
|
}
|
|
18688
18715
|
}
|
|
@@ -18694,7 +18721,11 @@ class HeatUtils {
|
|
|
18694
18721
|
* import { Heat } from "backtest-kit";
|
|
18695
18722
|
*
|
|
18696
18723
|
* // Strategy-specific heatmap
|
|
18697
|
-
* const stats = await Heat.getData(
|
|
18724
|
+
* const stats = await Heat.getData({
|
|
18725
|
+
* strategyName: "my-strategy",
|
|
18726
|
+
* exchangeName: "binance",
|
|
18727
|
+
* frameName: "frame1"
|
|
18728
|
+
* });
|
|
18698
18729
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
18699
18730
|
* console.log(`Total Symbols: ${stats.totalSymbols}`);
|
|
18700
18731
|
*
|
|
@@ -18708,7 +18739,11 @@ class HeatUtils {
|
|
|
18708
18739
|
* });
|
|
18709
18740
|
*
|
|
18710
18741
|
* // Generate and save report
|
|
18711
|
-
* await Heat.dump(
|
|
18742
|
+
* await Heat.dump({
|
|
18743
|
+
* strategyName: "my-strategy",
|
|
18744
|
+
* exchangeName: "binance",
|
|
18745
|
+
* frameName: "frame1"
|
|
18746
|
+
* }, false, "./reports");
|
|
18712
18747
|
* ```
|
|
18713
18748
|
*/
|
|
18714
18749
|
const Heat = new HeatUtils();
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -7588,15 +7588,27 @@ declare class HeatMarkdownService {
|
|
|
7588
7588
|
* import { Heat } from "backtest-kit";
|
|
7589
7589
|
*
|
|
7590
7590
|
* // Get raw heatmap data for a strategy
|
|
7591
|
-
* const stats = await Heat.getData(
|
|
7591
|
+
* const stats = await Heat.getData({
|
|
7592
|
+
* strategyName: "my-strategy",
|
|
7593
|
+
* exchangeName: "binance",
|
|
7594
|
+
* frameName: "frame1"
|
|
7595
|
+
* });
|
|
7592
7596
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
7593
7597
|
*
|
|
7594
7598
|
* // Generate markdown report
|
|
7595
|
-
* const markdown = await Heat.getReport(
|
|
7599
|
+
* const markdown = await Heat.getReport({
|
|
7600
|
+
* strategyName: "my-strategy",
|
|
7601
|
+
* exchangeName: "binance",
|
|
7602
|
+
* frameName: "frame1"
|
|
7603
|
+
* });
|
|
7596
7604
|
* console.log(markdown);
|
|
7597
7605
|
*
|
|
7598
7606
|
* // Save to disk
|
|
7599
|
-
* await Heat.dump(
|
|
7607
|
+
* await Heat.dump({
|
|
7608
|
+
* strategyName: "my-strategy",
|
|
7609
|
+
* exchangeName: "binance",
|
|
7610
|
+
* frameName: "frame1"
|
|
7611
|
+
* }, false, "./reports");
|
|
7600
7612
|
* ```
|
|
7601
7613
|
*/
|
|
7602
7614
|
declare class HeatUtils {
|
|
@@ -7606,14 +7618,14 @@ declare class HeatUtils {
|
|
|
7606
7618
|
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
7607
7619
|
* Data is automatically collected from all closed signals for the strategy.
|
|
7608
7620
|
*
|
|
7609
|
-
* @param
|
|
7610
|
-
* @param context - Execution context with exchangeName and frameName
|
|
7621
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
7611
7622
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
7612
7623
|
* @returns Promise resolving to heatmap statistics object
|
|
7613
7624
|
*
|
|
7614
7625
|
* @example
|
|
7615
7626
|
* ```typescript
|
|
7616
|
-
* const stats = await Heat.getData(
|
|
7627
|
+
* const stats = await Heat.getData({
|
|
7628
|
+
* strategyName: "my-strategy",
|
|
7617
7629
|
* exchangeName: "binance",
|
|
7618
7630
|
* frameName: "frame1"
|
|
7619
7631
|
* });
|
|
@@ -7628,7 +7640,8 @@ declare class HeatUtils {
|
|
|
7628
7640
|
* });
|
|
7629
7641
|
* ```
|
|
7630
7642
|
*/
|
|
7631
|
-
getData: (
|
|
7643
|
+
getData: (context: {
|
|
7644
|
+
strategyName: string;
|
|
7632
7645
|
exchangeName: string;
|
|
7633
7646
|
frameName: string;
|
|
7634
7647
|
}, backtest?: boolean) => Promise<HeatmapStatisticsModel>;
|
|
@@ -7638,15 +7651,15 @@ declare class HeatUtils {
|
|
|
7638
7651
|
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
7639
7652
|
* Symbols are sorted by Total PNL descending.
|
|
7640
7653
|
*
|
|
7641
|
-
* @param
|
|
7642
|
-
* @param context - Execution context with exchangeName and frameName
|
|
7654
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
7643
7655
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
7644
7656
|
* @param columns - Optional columns configuration for the report
|
|
7645
7657
|
* @returns Promise resolving to markdown formatted report string
|
|
7646
7658
|
*
|
|
7647
7659
|
* @example
|
|
7648
7660
|
* ```typescript
|
|
7649
|
-
* const markdown = await Heat.getReport(
|
|
7661
|
+
* const markdown = await Heat.getReport({
|
|
7662
|
+
* strategyName: "my-strategy",
|
|
7650
7663
|
* exchangeName: "binance",
|
|
7651
7664
|
* frameName: "frame1"
|
|
7652
7665
|
* });
|
|
@@ -7663,7 +7676,8 @@ declare class HeatUtils {
|
|
|
7663
7676
|
* // ...
|
|
7664
7677
|
* ```
|
|
7665
7678
|
*/
|
|
7666
|
-
getReport: (
|
|
7679
|
+
getReport: (context: {
|
|
7680
|
+
strategyName: string;
|
|
7667
7681
|
exchangeName: string;
|
|
7668
7682
|
frameName: string;
|
|
7669
7683
|
}, backtest?: boolean, columns?: Columns$2[]) => Promise<string>;
|
|
@@ -7673,8 +7687,7 @@ declare class HeatUtils {
|
|
|
7673
7687
|
* Creates directory if it doesn't exist.
|
|
7674
7688
|
* Default filename: {strategyName}.md
|
|
7675
7689
|
*
|
|
7676
|
-
* @param
|
|
7677
|
-
* @param context - Execution context with exchangeName and frameName
|
|
7690
|
+
* @param context - Execution context with strategyName, exchangeName and frameName
|
|
7678
7691
|
* @param backtest - True if backtest mode, false if live mode (default: false)
|
|
7679
7692
|
* @param path - Optional directory path to save report (default: "./dump/heatmap")
|
|
7680
7693
|
* @param columns - Optional columns configuration for the report
|
|
@@ -7682,19 +7695,22 @@ declare class HeatUtils {
|
|
|
7682
7695
|
* @example
|
|
7683
7696
|
* ```typescript
|
|
7684
7697
|
* // Save to default path: ./dump/heatmap/my-strategy.md
|
|
7685
|
-
* await Heat.dump(
|
|
7698
|
+
* await Heat.dump({
|
|
7699
|
+
* strategyName: "my-strategy",
|
|
7686
7700
|
* exchangeName: "binance",
|
|
7687
7701
|
* frameName: "frame1"
|
|
7688
7702
|
* });
|
|
7689
7703
|
*
|
|
7690
7704
|
* // Save to custom path: ./reports/my-strategy.md
|
|
7691
|
-
* await Heat.dump(
|
|
7705
|
+
* await Heat.dump({
|
|
7706
|
+
* strategyName: "my-strategy",
|
|
7692
7707
|
* exchangeName: "binance",
|
|
7693
7708
|
* frameName: "frame1"
|
|
7694
7709
|
* }, false, "./reports");
|
|
7695
7710
|
* ```
|
|
7696
7711
|
*/
|
|
7697
|
-
dump: (
|
|
7712
|
+
dump: (context: {
|
|
7713
|
+
strategyName: string;
|
|
7698
7714
|
exchangeName: string;
|
|
7699
7715
|
frameName: string;
|
|
7700
7716
|
}, backtest?: boolean, path?: string, columns?: Columns$2[]) => Promise<void>;
|
|
@@ -7707,7 +7723,11 @@ declare class HeatUtils {
|
|
|
7707
7723
|
* import { Heat } from "backtest-kit";
|
|
7708
7724
|
*
|
|
7709
7725
|
* // Strategy-specific heatmap
|
|
7710
|
-
* const stats = await Heat.getData(
|
|
7726
|
+
* const stats = await Heat.getData({
|
|
7727
|
+
* strategyName: "my-strategy",
|
|
7728
|
+
* exchangeName: "binance",
|
|
7729
|
+
* frameName: "frame1"
|
|
7730
|
+
* });
|
|
7711
7731
|
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
7712
7732
|
* console.log(`Total Symbols: ${stats.totalSymbols}`);
|
|
7713
7733
|
*
|
|
@@ -7721,7 +7741,11 @@ declare class HeatUtils {
|
|
|
7721
7741
|
* });
|
|
7722
7742
|
*
|
|
7723
7743
|
* // Generate and save report
|
|
7724
|
-
* await Heat.dump(
|
|
7744
|
+
* await Heat.dump({
|
|
7745
|
+
* strategyName: "my-strategy",
|
|
7746
|
+
* exchangeName: "binance",
|
|
7747
|
+
* frameName: "frame1"
|
|
7748
|
+
* }, false, "./reports");
|
|
7725
7749
|
* ```
|
|
7726
7750
|
*/
|
|
7727
7751
|
declare const Heat: HeatUtils;
|
|
@@ -10127,10 +10151,10 @@ declare class StrategyCoreService {
|
|
|
10127
10151
|
/**
|
|
10128
10152
|
* Validates strategy and associated risk configuration.
|
|
10129
10153
|
*
|
|
10130
|
-
* Memoized to avoid redundant validations for the same symbol-strategy
|
|
10154
|
+
* Memoized to avoid redundant validations for the same symbol-strategy-exchange-frame combination.
|
|
10131
10155
|
* Logs validation activity.
|
|
10132
10156
|
* @param symbol - Trading pair symbol
|
|
10133
|
-
* @param
|
|
10157
|
+
* @param context - Execution context with strategyName, exchangeName, frameName
|
|
10134
10158
|
* @returns Promise that resolves when validation is complete
|
|
10135
10159
|
*/
|
|
10136
10160
|
private validate;
|
|
@@ -10319,9 +10343,9 @@ declare class RiskGlobalService {
|
|
|
10319
10343
|
private readonly riskValidationService;
|
|
10320
10344
|
/**
|
|
10321
10345
|
* Validates risk configuration.
|
|
10322
|
-
* Memoized to avoid redundant validations for the same risk
|
|
10346
|
+
* Memoized to avoid redundant validations for the same risk-exchange-frame combination.
|
|
10323
10347
|
* Logs validation activity.
|
|
10324
|
-
* @param
|
|
10348
|
+
* @param payload - Payload with riskName, exchangeName and frameName
|
|
10325
10349
|
* @returns Promise that resolves when validation is complete
|
|
10326
10350
|
*/
|
|
10327
10351
|
private validate;
|
|
@@ -11721,9 +11745,9 @@ declare class PartialGlobalService {
|
|
|
11721
11745
|
private readonly riskValidationService;
|
|
11722
11746
|
/**
|
|
11723
11747
|
* Validates strategy and associated risk configuration.
|
|
11724
|
-
* Memoized to avoid redundant validations for the same strategy.
|
|
11748
|
+
* Memoized to avoid redundant validations for the same strategy-exchange-frame combination.
|
|
11725
11749
|
*
|
|
11726
|
-
* @param
|
|
11750
|
+
* @param context - Context with strategyName, exchangeName and frameName
|
|
11727
11751
|
* @param methodName - Name of the calling method for error tracking
|
|
11728
11752
|
*/
|
|
11729
11753
|
private validate;
|