backtest-kit 1.5.39 → 1.5.41

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 CHANGED
@@ -4376,8 +4376,12 @@ class MergeRisk {
4376
4376
  backtest$1.loggerService.info("MergeRisk checkSignal", {
4377
4377
  params,
4378
4378
  });
4379
- const riskCheck = await Promise.all(this._riskList.map(async (risk) => await risk.checkSignal(params)));
4380
- return riskCheck.every((isSafe) => isSafe);
4379
+ for (const risk of this._riskList) {
4380
+ if (await functoolsKit.not(risk.checkSignal(params))) {
4381
+ return false;
4382
+ }
4383
+ }
4384
+ return true;
4381
4385
  }
4382
4386
  /**
4383
4387
  * Registers a signal with all child risk profiles.
@@ -4485,7 +4489,8 @@ class RiskUtils {
4485
4489
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4486
4490
  riskName &&
4487
4491
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
4488
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
4492
+ riskList &&
4493
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
4489
4494
  }
4490
4495
  return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
4491
4496
  };
@@ -4540,7 +4545,8 @@ class RiskUtils {
4540
4545
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4541
4546
  riskName &&
4542
4547
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
4543
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
4548
+ riskList &&
4549
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
4544
4550
  }
4545
4551
  return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
4546
4552
  };
@@ -4587,7 +4593,8 @@ class RiskUtils {
4587
4593
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4588
4594
  riskName &&
4589
4595
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
4590
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
4596
+ riskList &&
4597
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
4591
4598
  }
4592
4599
  await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
4593
4600
  };
package/build/index.mjs CHANGED
@@ -4374,8 +4374,12 @@ class MergeRisk {
4374
4374
  backtest$1.loggerService.info("MergeRisk checkSignal", {
4375
4375
  params,
4376
4376
  });
4377
- const riskCheck = await Promise.all(this._riskList.map(async (risk) => await risk.checkSignal(params)));
4378
- return riskCheck.every((isSafe) => isSafe);
4377
+ for (const risk of this._riskList) {
4378
+ if (await not(risk.checkSignal(params))) {
4379
+ return false;
4380
+ }
4381
+ }
4382
+ return true;
4379
4383
  }
4380
4384
  /**
4381
4385
  * Registers a signal with all child risk profiles.
@@ -4483,7 +4487,8 @@ class RiskUtils {
4483
4487
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4484
4488
  riskName &&
4485
4489
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA);
4486
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
4490
+ riskList &&
4491
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_DATA));
4487
4492
  }
4488
4493
  return await backtest$1.riskMarkdownService.getData(symbol, strategyName, backtest);
4489
4494
  };
@@ -4538,7 +4543,8 @@ class RiskUtils {
4538
4543
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4539
4544
  riskName &&
4540
4545
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT);
4541
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
4546
+ riskList &&
4547
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_GET_REPORT));
4542
4548
  }
4543
4549
  return await backtest$1.riskMarkdownService.getReport(symbol, strategyName, backtest, columns);
4544
4550
  };
@@ -4585,7 +4591,8 @@ class RiskUtils {
4585
4591
  const { riskName, riskList } = backtest$1.strategySchemaService.get(strategyName);
4586
4592
  riskName &&
4587
4593
  backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP);
4588
- riskList && riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
4594
+ riskList &&
4595
+ riskList.forEach((riskName) => backtest$1.riskValidationService.validate(riskName, RISK_METHOD_NAME_DUMP));
4589
4596
  }
4590
4597
  await backtest$1.riskMarkdownService.dump(symbol, strategyName, backtest, path, columns);
4591
4598
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backtest-kit",
3
- "version": "1.5.39",
3
+ "version": "1.5.41",
4
4
  "description": "A TypeScript library for trading system backtest",
5
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -2,51 +2,153 @@ import * as di_scoped from 'di-scoped';
2
2
  import * as functools_kit from 'functools-kit';
3
3
  import { Subject } from 'functools-kit';
4
4
 
5
+ declare const GLOBAL_CONFIG: {
6
+ /**
7
+ * Time to wait for scheduled signal to activate (in minutes)
8
+ * If signal does not activate within this time, it will be cancelled.
9
+ */
10
+ CC_SCHEDULE_AWAIT_MINUTES: number;
11
+ /**
12
+ * Number of candles to use for average price calculation (VWAP)
13
+ * Default: 5 candles (last 5 minutes when using 1m interval)
14
+ */
15
+ CC_AVG_PRICE_CANDLES_COUNT: number;
16
+ /**
17
+ * Slippage percentage applied to entry and exit prices.
18
+ * Simulates market impact and order book depth.
19
+ * Applied twice (entry and exit) for realistic execution simulation.
20
+ * Default: 0.1% per transaction
21
+ */
22
+ CC_PERCENT_SLIPPAGE: number;
23
+ /**
24
+ * Fee percentage charged per transaction.
25
+ * Applied twice (entry and exit) for total fee calculation.
26
+ * Default: 0.1% per transaction (total 0.2%)
27
+ */
28
+ CC_PERCENT_FEE: number;
29
+ /**
30
+ * Minimum TakeProfit distance from priceOpen (percentage)
31
+ * Must be greater than (slippage + fees) to ensure profitable trades
32
+ *
33
+ * Calculation:
34
+ * - Slippage effect: ~0.2% (0.1% × 2 transactions)
35
+ * - Fees: 0.2% (0.1% × 2 transactions)
36
+ * - Minimum profit buffer: 0.1%
37
+ * - Total: 0.5%
38
+ *
39
+ * Default: 0.5% (covers all costs + minimum profit margin)
40
+ */
41
+ CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
42
+ /**
43
+ * Minimum StopLoss distance from priceOpen (percentage)
44
+ * Prevents signals from being immediately stopped out due to price volatility
45
+ * Default: 0.5% (buffer to avoid instant stop loss on normal market fluctuations)
46
+ */
47
+ CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
48
+ /**
49
+ * Maximum StopLoss distance from priceOpen (percentage)
50
+ * Prevents catastrophic losses from extreme StopLoss values
51
+ * Default: 20% (one signal cannot lose more than 20% of position)
52
+ */
53
+ CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
54
+ /**
55
+ * Maximum signal lifetime in minutes
56
+ * Prevents eternal signals that block risk limits for weeks/months
57
+ * Default: 1440 minutes (1 day)
58
+ */
59
+ CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
60
+ /**
61
+ * Maximum time allowed for signal generation (in seconds).
62
+ * Prevents long-running or stuck signal generation routines from blocking
63
+ * execution or consuming resources indefinitely. If generation exceeds this
64
+ * threshold the attempt should be aborted, logged and optionally retried.
65
+ *
66
+ * Default: 180 seconds (3 minutes)
67
+ */
68
+ CC_MAX_SIGNAL_GENERATION_SECONDS: number;
69
+ /**
70
+ * Number of retries for getCandles function
71
+ * Default: 3 retries
72
+ */
73
+ CC_GET_CANDLES_RETRY_COUNT: number;
74
+ /**
75
+ * Delay between retries for getCandles function (in milliseconds)
76
+ * Default: 5000 ms (5 seconds)
77
+ */
78
+ CC_GET_CANDLES_RETRY_DELAY_MS: number;
79
+ /**
80
+ * Maximum allowed deviation factor for price anomaly detection.
81
+ * Price should not be more than this factor lower than reference price.
82
+ *
83
+ * Reasoning:
84
+ * - Incomplete candles from Binance API typically have prices near 0 (e.g., $0.01-1)
85
+ * - Normal BTC price ranges: $20,000-100,000
86
+ * - Factor 1000 catches prices below $20-100 when median is $20,000-100,000
87
+ * - Factor 100 would be too permissive (allows $200 when median is $20,000)
88
+ * - Factor 10000 might be too strict for low-cap altcoins
89
+ *
90
+ * Example: BTC at $50,000 median → threshold $50 (catches $0.01-1 anomalies)
91
+ */
92
+ CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
93
+ /**
94
+ * Minimum number of candles required for reliable median calculation.
95
+ * Below this threshold, use simple average instead of median.
96
+ *
97
+ * Reasoning:
98
+ * - Each candle provides 4 price points (OHLC)
99
+ * - 5 candles = 20 price points, sufficient for robust median calculation
100
+ * - Below 5 candles, single anomaly can heavily skew median
101
+ * - Statistical rule of thumb: minimum 7-10 data points for median stability
102
+ * - Average is more stable than median for small datasets (n < 20)
103
+ *
104
+ * Example: 3 candles = 12 points (use average), 5 candles = 20 points (use median)
105
+ */
106
+ CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
107
+ /**
108
+ * Controls visibility of signal notes in markdown report tables.
109
+ * When enabled, the "Note" column will be displayed in all markdown reports
110
+ * (backtest, live, schedule, risk, etc.)
111
+ *
112
+ * Default: false (notes are hidden to reduce table width and improve readability)
113
+ */
114
+ CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
115
+ };
5
116
  /**
6
- * Execution context containing runtime parameters for strategy/exchange operations.
7
- *
8
- * Propagated through ExecutionContextService to provide implicit context
9
- * for getCandles(), tick(), backtest() and other operations.
117
+ * Type for global configuration object.
10
118
  */
11
- interface IExecutionContext {
12
- /** Trading pair symbol (e.g., "BTCUSDT") */
13
- symbol: string;
14
- /** Current timestamp for operation */
15
- when: Date;
16
- /** Whether running in backtest mode (true) or live mode (false) */
17
- backtest: boolean;
18
- }
119
+ type GlobalConfig = typeof GLOBAL_CONFIG;
120
+
19
121
  /**
20
- * Scoped service for execution context propagation.
21
- *
22
- * Uses di-scoped for implicit context passing without explicit parameters.
23
- * Context includes symbol, when (timestamp), and backtest flag.
24
- *
25
- * Used by GlobalServices to inject context into operations.
122
+ * Mapping of available table/markdown reports to their column definitions.
26
123
  *
27
- * @example
28
- * ```typescript
29
- * ExecutionContextService.runInContext(
30
- * async () => {
31
- * // Inside this callback, context is automatically available
32
- * return await someOperation();
33
- * },
34
- * { symbol: "BTCUSDT", when: new Date(), backtest: true }
35
- * );
36
- * ```
124
+ * Each property references a column definition object imported from
125
+ * `src/assets/*.columns`. These are used by markdown/report generators
126
+ * (backtest, live, schedule, risk, heat, performance, partial, walker).
37
127
  */
38
- declare const ExecutionContextService: (new () => {
39
- readonly context: IExecutionContext;
40
- }) & Omit<{
41
- new (context: IExecutionContext): {
42
- readonly context: IExecutionContext;
43
- };
44
- }, "prototype"> & di_scoped.IScopedClassRun<[context: IExecutionContext]>;
128
+ declare const COLUMN_CONFIG: {
129
+ /** Columns used in backtest markdown tables and reports */
130
+ backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
131
+ /** Columns used by heatmap / heat reports */
132
+ heat_columns: ColumnModel<IHeatmapRow>[];
133
+ /** Columns for live trading reports and logs */
134
+ live_columns: ColumnModel<TickEvent>[];
135
+ /** Columns for partial-results / incremental reports */
136
+ partial_columns: ColumnModel<PartialEvent>[];
137
+ /** Columns for performance summary reports */
138
+ performance_columns: ColumnModel<MetricStats>[];
139
+ /** Columns for risk-related reports */
140
+ risk_columns: ColumnModel<RiskEvent>[];
141
+ /** Columns for scheduled report output */
142
+ schedule_columns: ColumnModel<ScheduledEvent>[];
143
+ /** Walker: PnL summary columns */
144
+ walker_pnl_columns: ColumnModel<SignalData$1>[];
145
+ /** Walker: strategy-level summary columns */
146
+ walker_strategy_columns: ColumnModel<IStrategyResult>[];
147
+ };
45
148
  /**
46
- * Type helper for ExecutionContextService instance.
47
- * Used for dependency injection type annotations.
149
+ * Type for the column configuration object.
48
150
  */
49
- type TExecutionContextService = InstanceType<typeof ExecutionContextService>;
151
+ type ColumnConfig = typeof COLUMN_CONFIG;
50
152
 
51
153
  /**
52
154
  * Interface representing a logging mechanism for the swarm system.
@@ -77,50 +179,264 @@ interface ILogger {
77
179
  }
78
180
 
79
181
  /**
80
- * Candle time interval for fetching historical data.
81
- */
82
- type CandleInterval = "1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "8h";
83
- /**
84
- * Single OHLCV candle data point.
85
- * Used for VWAP calculation and backtesting.
86
- */
87
- interface ICandleData {
88
- /** Unix timestamp in milliseconds when candle opened */
89
- timestamp: number;
90
- /** Opening price at candle start */
91
- open: number;
92
- /** Highest price during candle period */
93
- high: number;
94
- /** Lowest price during candle period */
95
- low: number;
96
- /** Closing price at candle end */
97
- close: number;
98
- /** Trading volume during candle period */
99
- volume: number;
100
- }
101
- /**
102
- * Exchange parameters passed to ClientExchange constructor.
103
- * Combines schema with runtime dependencies.
182
+ * Sets custom logger implementation for the framework.
183
+ *
184
+ * All log messages from internal services will be forwarded to the provided logger
185
+ * with automatic context injection (strategyName, exchangeName, symbol, etc.).
186
+ *
187
+ * @param logger - Custom logger implementing ILogger interface
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * setLogger({
192
+ * log: (topic, ...args) => console.log(topic, args),
193
+ * debug: (topic, ...args) => console.debug(topic, args),
194
+ * info: (topic, ...args) => console.info(topic, args),
195
+ * });
196
+ * ```
104
197
  */
105
- interface IExchangeParams extends IExchangeSchema {
106
- /** Logger service for debug output */
107
- logger: ILogger;
108
- /** Execution context service (symbol, when, backtest flag) */
109
- execution: TExecutionContextService;
110
- }
198
+ declare function setLogger(logger: ILogger): void;
111
199
  /**
112
- * Optional callbacks for exchange data events.
200
+ * Sets global configuration parameters for the framework.
201
+ * @param config - Partial configuration object to override default settings
202
+ * @param _unsafe - Skip config validations - required for testbed
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * setConfig({
207
+ * CC_SCHEDULE_AWAIT_MINUTES: 90,
208
+ * });
209
+ * ```
113
210
  */
114
- interface IExchangeCallbacks {
115
- /** Called when candle data is fetched */
116
- onCandleData: (symbol: string, interval: CandleInterval, since: Date, limit: number, data: ICandleData[]) => void;
117
- }
211
+ declare function setConfig(config: Partial<GlobalConfig>, _unsafe?: boolean): void;
118
212
  /**
119
- * Exchange schema registered via addExchange().
120
- * Defines candle data source and formatting logic.
213
+ * Retrieves a copy of the current global configuration.
214
+ *
215
+ * Returns a shallow copy of the current GLOBAL_CONFIG to prevent accidental mutations.
216
+ * Use this to inspect the current configuration state without modifying it.
217
+ *
218
+ * @returns {GlobalConfig} A copy of the current global configuration object
219
+ *
220
+ * @example
221
+ * ```typescript
222
+ * const currentConfig = getConfig();
223
+ * console.log(currentConfig.CC_SCHEDULE_AWAIT_MINUTES);
224
+ * ```
121
225
  */
122
- interface IExchangeSchema {
123
- /** Unique exchange identifier for registration */
226
+ declare function getConfig(): {
227
+ CC_SCHEDULE_AWAIT_MINUTES: number;
228
+ CC_AVG_PRICE_CANDLES_COUNT: number;
229
+ CC_PERCENT_SLIPPAGE: number;
230
+ CC_PERCENT_FEE: number;
231
+ CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
232
+ CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
233
+ CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
234
+ CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
235
+ CC_MAX_SIGNAL_GENERATION_SECONDS: number;
236
+ CC_GET_CANDLES_RETRY_COUNT: number;
237
+ CC_GET_CANDLES_RETRY_DELAY_MS: number;
238
+ CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
239
+ CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
240
+ CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
241
+ };
242
+ /**
243
+ * Retrieves the default configuration object for the framework.
244
+ *
245
+ * Returns a reference to the default configuration with all preset values.
246
+ * Use this to see what configuration options are available and their default values.
247
+ *
248
+ * @returns {GlobalConfig} The default configuration object
249
+ *
250
+ * @example
251
+ * ```typescript
252
+ * const defaultConfig = getDefaultConfig();
253
+ * console.log(defaultConfig.CC_SCHEDULE_AWAIT_MINUTES);
254
+ * ```
255
+ */
256
+ declare function getDefaultConfig(): Readonly<{
257
+ CC_SCHEDULE_AWAIT_MINUTES: number;
258
+ CC_AVG_PRICE_CANDLES_COUNT: number;
259
+ CC_PERCENT_SLIPPAGE: number;
260
+ CC_PERCENT_FEE: number;
261
+ CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
262
+ CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
263
+ CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
264
+ CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
265
+ CC_MAX_SIGNAL_GENERATION_SECONDS: number;
266
+ CC_GET_CANDLES_RETRY_COUNT: number;
267
+ CC_GET_CANDLES_RETRY_DELAY_MS: number;
268
+ CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
269
+ CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
270
+ CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
271
+ }>;
272
+ /**
273
+ * Sets custom column configurations for markdown report generation.
274
+ *
275
+ * Allows overriding default column definitions for any report type.
276
+ * All columns are validated before assignment to ensure structural correctness.
277
+ *
278
+ * @param columns - Partial column configuration object to override default column settings
279
+ * @param _unsafe - Skip column validations - required for testbed
280
+ *
281
+ * @example
282
+ * ```typescript
283
+ * setColumns({
284
+ * backtest_columns: [
285
+ * {
286
+ * key: "customId",
287
+ * label: "Custom ID",
288
+ * format: (data) => data.signal.id,
289
+ * isVisible: () => true
290
+ * }
291
+ * ],
292
+ * });
293
+ * ```
294
+ *
295
+ * @throws {Error} If column configuration is invalid
296
+ */
297
+ declare function setColumns(columns: Partial<ColumnConfig>, _unsafe?: boolean): void;
298
+ /**
299
+ * Retrieves a copy of the current column configuration for markdown report generation.
300
+ *
301
+ * Returns a shallow copy of the current COLUMN_CONFIG to prevent accidental mutations.
302
+ * Use this to inspect the current column definitions without modifying them.
303
+ *
304
+ * @returns {ColumnConfig} A copy of the current column configuration object
305
+ *
306
+ * @example
307
+ * ```typescript
308
+ * const currentColumns = getColumns();
309
+ * console.log(currentColumns.backtest_columns.length);
310
+ * ```
311
+ */
312
+ declare function getColumns(): {
313
+ backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
314
+ heat_columns: ColumnModel<IHeatmapRow>[];
315
+ live_columns: ColumnModel<TickEvent>[];
316
+ partial_columns: ColumnModel<PartialEvent>[];
317
+ performance_columns: ColumnModel<MetricStats>[];
318
+ risk_columns: ColumnModel<RiskEvent>[];
319
+ schedule_columns: ColumnModel<ScheduledEvent>[];
320
+ walker_pnl_columns: ColumnModel<SignalData$1>[];
321
+ walker_strategy_columns: ColumnModel<IStrategyResult>[];
322
+ };
323
+ /**
324
+ * Retrieves the default column configuration object for markdown report generation.
325
+ *
326
+ * Returns a reference to the default column definitions with all preset values.
327
+ * Use this to see what column options are available and their default definitions.
328
+ *
329
+ * @returns {ColumnConfig} The default column configuration object
330
+ *
331
+ * @example
332
+ * ```typescript
333
+ * const defaultColumns = getDefaultColumns();
334
+ * console.log(defaultColumns.backtest_columns);
335
+ * ```
336
+ */
337
+ declare function getDefaultColumns(): Readonly<{
338
+ backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
339
+ heat_columns: ColumnModel<IHeatmapRow>[];
340
+ live_columns: ColumnModel<TickEvent>[];
341
+ partial_columns: ColumnModel<PartialEvent>[];
342
+ performance_columns: ColumnModel<MetricStats>[];
343
+ risk_columns: ColumnModel<RiskEvent>[];
344
+ schedule_columns: ColumnModel<ScheduledEvent>[];
345
+ walker_pnl_columns: ColumnModel<SignalData$1>[];
346
+ walker_strategy_columns: ColumnModel<IStrategyResult>[];
347
+ }>;
348
+
349
+ /**
350
+ * Execution context containing runtime parameters for strategy/exchange operations.
351
+ *
352
+ * Propagated through ExecutionContextService to provide implicit context
353
+ * for getCandles(), tick(), backtest() and other operations.
354
+ */
355
+ interface IExecutionContext {
356
+ /** Trading pair symbol (e.g., "BTCUSDT") */
357
+ symbol: string;
358
+ /** Current timestamp for operation */
359
+ when: Date;
360
+ /** Whether running in backtest mode (true) or live mode (false) */
361
+ backtest: boolean;
362
+ }
363
+ /**
364
+ * Scoped service for execution context propagation.
365
+ *
366
+ * Uses di-scoped for implicit context passing without explicit parameters.
367
+ * Context includes symbol, when (timestamp), and backtest flag.
368
+ *
369
+ * Used by GlobalServices to inject context into operations.
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * ExecutionContextService.runInContext(
374
+ * async () => {
375
+ * // Inside this callback, context is automatically available
376
+ * return await someOperation();
377
+ * },
378
+ * { symbol: "BTCUSDT", when: new Date(), backtest: true }
379
+ * );
380
+ * ```
381
+ */
382
+ declare const ExecutionContextService: (new () => {
383
+ readonly context: IExecutionContext;
384
+ }) & Omit<{
385
+ new (context: IExecutionContext): {
386
+ readonly context: IExecutionContext;
387
+ };
388
+ }, "prototype"> & di_scoped.IScopedClassRun<[context: IExecutionContext]>;
389
+ /**
390
+ * Type helper for ExecutionContextService instance.
391
+ * Used for dependency injection type annotations.
392
+ */
393
+ type TExecutionContextService = InstanceType<typeof ExecutionContextService>;
394
+
395
+ /**
396
+ * Candle time interval for fetching historical data.
397
+ */
398
+ type CandleInterval = "1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "8h";
399
+ /**
400
+ * Single OHLCV candle data point.
401
+ * Used for VWAP calculation and backtesting.
402
+ */
403
+ interface ICandleData {
404
+ /** Unix timestamp in milliseconds when candle opened */
405
+ timestamp: number;
406
+ /** Opening price at candle start */
407
+ open: number;
408
+ /** Highest price during candle period */
409
+ high: number;
410
+ /** Lowest price during candle period */
411
+ low: number;
412
+ /** Closing price at candle end */
413
+ close: number;
414
+ /** Trading volume during candle period */
415
+ volume: number;
416
+ }
417
+ /**
418
+ * Exchange parameters passed to ClientExchange constructor.
419
+ * Combines schema with runtime dependencies.
420
+ */
421
+ interface IExchangeParams extends IExchangeSchema {
422
+ /** Logger service for debug output */
423
+ logger: ILogger;
424
+ /** Execution context service (symbol, when, backtest flag) */
425
+ execution: TExecutionContextService;
426
+ }
427
+ /**
428
+ * Optional callbacks for exchange data events.
429
+ */
430
+ interface IExchangeCallbacks {
431
+ /** Called when candle data is fetched */
432
+ onCandleData: (symbol: string, interval: CandleInterval, since: Date, limit: number, data: ICandleData[]) => void;
433
+ }
434
+ /**
435
+ * Exchange schema registered via addExchange().
436
+ * Defines candle data source and formatting logic.
437
+ */
438
+ interface IExchangeSchema {
439
+ /** Unique exchange identifier for registration */
124
440
  exchangeName: ExchangeName;
125
441
  /** Optional developer note for documentation */
126
442
  note?: string;
@@ -897,536 +1213,175 @@ interface IStrategyTickResultCancelled {
897
1213
  backtest: boolean;
898
1214
  }
899
1215
  /**
900
- * Discriminated union of all tick results.
901
- * Use type guards: `result.action === "closed"` for type safety.
902
- */
903
- type IStrategyTickResult = IStrategyTickResultIdle | IStrategyTickResultScheduled | IStrategyTickResultOpened | IStrategyTickResultActive | IStrategyTickResultClosed | IStrategyTickResultCancelled;
904
- /**
905
- * Backtest returns closed result (TP/SL or time_expired) or cancelled result (scheduled signal never activated).
906
- */
907
- type IStrategyBacktestResult = IStrategyTickResultClosed | IStrategyTickResultCancelled;
908
- /**
909
- * Unique strategy identifier.
910
- */
911
- type StrategyName = string;
912
-
913
- /**
914
- * Statistical data calculated from backtest results.
915
- *
916
- * All numeric values are null if calculation is unsafe (NaN, Infinity, etc).
917
- * Provides comprehensive metrics for strategy performance analysis.
918
- *
919
- * @example
920
- * ```typescript
921
- * const stats = await Backtest.getData("my-strategy");
922
- *
923
- * console.log(`Total signals: ${stats.totalSignals}`);
924
- * console.log(`Win rate: ${stats.winRate}%`);
925
- * console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
926
- *
927
- * // Access raw signal data
928
- * stats.signalList.forEach(signal => {
929
- * console.log(`Signal ${signal.signal.id}: ${signal.pnl.pnlPercentage}%`);
930
- * });
931
- * ```
932
- */
933
- interface BacktestStatisticsModel {
934
- /** Array of all closed signals with full details (price, PNL, timestamps, etc.) */
935
- signalList: IStrategyTickResultClosed[];
936
- /** Total number of closed signals */
937
- totalSignals: number;
938
- /** Number of winning signals (PNL > 0) */
939
- winCount: number;
940
- /** Number of losing signals (PNL < 0) */
941
- lossCount: number;
942
- /** Win rate as percentage (0-100), null if unsafe. Higher is better. */
943
- winRate: number | null;
944
- /** Average PNL per signal as percentage, null if unsafe. Higher is better. */
945
- avgPnl: number | null;
946
- /** Cumulative PNL across all signals as percentage, null if unsafe. Higher is better. */
947
- totalPnl: number | null;
948
- /** Standard deviation of returns (volatility metric), null if unsafe. Lower is better. */
949
- stdDev: number | null;
950
- /** Sharpe Ratio (risk-adjusted return = avgPnl / stdDev), null if unsafe. Higher is better. */
951
- sharpeRatio: number | null;
952
- /** Annualized Sharpe Ratio (sharpeRatio × √365), null if unsafe. Higher is better. */
953
- annualizedSharpeRatio: number | null;
954
- /** Certainty Ratio (avgWin / |avgLoss|), null if unsafe. Higher is better. */
955
- certaintyRatio: number | null;
956
- /** Expected yearly returns based on average trade duration and PNL, null if unsafe. Higher is better. */
957
- expectedYearlyReturns: number | null;
958
- }
959
-
960
- /**
961
- * Optimization metric for comparing strategies.
962
- * Higher values are always better (metric is maximized).
963
- */
964
- type WalkerMetric = "sharpeRatio" | "annualizedSharpeRatio" | "winRate" | "totalPnl" | "certaintyRatio" | "avgPnl" | "expectedYearlyReturns";
965
- /**
966
- * Walker schema registered via addWalker().
967
- * Defines A/B testing configuration for multiple strategies.
968
- */
969
- interface IWalkerSchema {
970
- /** Unique walker identifier for registration */
971
- walkerName: WalkerName;
972
- /** Optional developer note for documentation */
973
- note?: string;
974
- /** Exchange to use for backtesting all strategies */
975
- exchangeName: ExchangeName;
976
- /** Timeframe generator to use for backtesting all strategies */
977
- frameName: FrameName;
978
- /** List of strategy names to compare (must be registered via addStrategy) */
979
- strategies: StrategyName[];
980
- /** Metric to optimize (default: "sharpeRatio") */
981
- metric?: WalkerMetric;
982
- /** Optional lifecycle event callbacks */
983
- callbacks?: Partial<IWalkerCallbacks>;
984
- }
985
- /**
986
- * Optional lifecycle callbacks for walker events.
987
- * Called during strategy comparison process.
988
- */
989
- interface IWalkerCallbacks {
990
- /** Called when starting to test a specific strategy */
991
- onStrategyStart: (strategyName: StrategyName, symbol: string) => void;
992
- /** Called when a strategy backtest completes */
993
- onStrategyComplete: (strategyName: StrategyName, symbol: string, stats: BacktestStatisticsModel, metric: number | null) => void;
994
- /** Called when a strategy backtest fails with an error */
995
- onStrategyError: (strategyName: StrategyName, symbol: string, error: Error | unknown) => void;
996
- /** Called when all strategies have been tested */
997
- onComplete: (results: IWalkerResults) => void;
998
- }
999
- /**
1000
- * Result for a single strategy in the comparison.
1001
- */
1002
- interface IWalkerStrategyResult {
1003
- /** Strategy name */
1004
- strategyName: StrategyName;
1005
- /** Backtest statistics for this strategy */
1006
- stats: BacktestStatisticsModel;
1007
- /** Metric value used for comparison (null if invalid) */
1008
- metric: number | null;
1009
- /** Rank position (1 = best, 2 = second best, etc.) */
1010
- rank: number;
1011
- }
1012
- /**
1013
- * Complete walker results after comparing all strategies.
1014
- */
1015
- interface IWalkerResults extends WalkerCompleteContract {
1016
- /** Symbol tested */
1017
- symbol: string;
1018
- /** Exchange used */
1019
- exchangeName: ExchangeName;
1020
- /** Walker name */
1021
- walkerName: WalkerName;
1022
- /** Frame used */
1023
- frameName: FrameName;
1024
- }
1025
- /**
1026
- * Unique walker identifier.
1027
- */
1028
- type WalkerName = string;
1029
-
1030
- /**
1031
- * Contract for walker completion events.
1032
- *
1033
- * Emitted when all strategies have been tested and final results are available.
1034
- * Contains complete results of the walker comparison including the best strategy.
1035
- *
1036
- * @example
1037
- * ```typescript
1038
- * import { walkerCompleteSubject } from "backtest-kit";
1039
- *
1040
- * walkerCompleteSubject
1041
- * .filter((event) => event.symbol === "BTCUSDT")
1042
- * .connect((event) => {
1043
- * console.log("Walker completed:", event.walkerName);
1044
- * console.log("Best strategy:", event.bestStrategy);
1045
- * console.log("Best metric:", event.bestMetric);
1046
- * });
1047
- * ```
1048
- */
1049
- interface WalkerCompleteContract {
1050
- /** walkerName - Walker name */
1051
- walkerName: WalkerName;
1052
- /** symbol - Symbol tested */
1053
- symbol: string;
1054
- /** exchangeName - Exchange used */
1055
- exchangeName: ExchangeName;
1056
- /** frameName - Frame used */
1057
- frameName: FrameName;
1058
- /** metric - Metric used for optimization */
1059
- metric: WalkerMetric;
1060
- /** totalStrategies - Total number of strategies tested */
1061
- totalStrategies: number;
1062
- /** bestStrategy - Best performing strategy name */
1063
- bestStrategy: StrategyName | null;
1064
- /** bestMetric - Best metric value achieved */
1065
- bestMetric: number | null;
1066
- /** bestStats - Best strategy statistics */
1067
- bestStats: BacktestStatisticsModel | null;
1068
- }
1069
-
1070
- /**
1071
- * Signal data for PNL table.
1072
- * Represents a single closed signal with essential trading information.
1073
- */
1074
- interface SignalData$1 {
1075
- /** Strategy that generated this signal */
1076
- strategyName: StrategyName;
1077
- /** Unique signal identifier */
1078
- signalId: string;
1079
- /** Trading pair symbol */
1080
- symbol: string;
1081
- /** Position type (long/short) */
1082
- position: string;
1083
- /** PNL as percentage */
1084
- pnl: number;
1085
- /** Reason why signal was closed */
1086
- closeReason: string;
1087
- /** Timestamp when signal opened */
1088
- openTime: number;
1089
- /** Timestamp when signal closed */
1090
- closeTime: number;
1091
- }
1092
- /**
1093
- * Strategy result entry for comparison table.
1094
- * Contains strategy name, full statistics, and metric value for ranking.
1095
- */
1096
- interface IStrategyResult {
1097
- /** Strategy name */
1098
- strategyName: StrategyName;
1099
- /** Complete backtest statistics for this strategy */
1100
- stats: BacktestStatisticsModel;
1101
- /** Value of the optimization metric (null if invalid) */
1102
- metricValue: number | null;
1103
- }
1104
- /**
1105
- * Alias for walker statistics result interface.
1106
- * Used for clarity in markdown service context.
1107
- *
1108
- * Extends IWalkerResults with additional strategy comparison data.
1109
- */
1110
- interface WalkerStatisticsModel extends WalkerCompleteContract {
1111
- /** Array of all strategy results for comparison and analysis */
1112
- strategyResults: IStrategyResult[];
1113
- }
1114
-
1115
- declare const GLOBAL_CONFIG: {
1116
- /**
1117
- * Time to wait for scheduled signal to activate (in minutes)
1118
- * If signal does not activate within this time, it will be cancelled.
1119
- */
1120
- CC_SCHEDULE_AWAIT_MINUTES: number;
1121
- /**
1122
- * Number of candles to use for average price calculation (VWAP)
1123
- * Default: 5 candles (last 5 minutes when using 1m interval)
1124
- */
1125
- CC_AVG_PRICE_CANDLES_COUNT: number;
1126
- /**
1127
- * Slippage percentage applied to entry and exit prices.
1128
- * Simulates market impact and order book depth.
1129
- * Applied twice (entry and exit) for realistic execution simulation.
1130
- * Default: 0.1% per transaction
1131
- */
1132
- CC_PERCENT_SLIPPAGE: number;
1133
- /**
1134
- * Fee percentage charged per transaction.
1135
- * Applied twice (entry and exit) for total fee calculation.
1136
- * Default: 0.1% per transaction (total 0.2%)
1137
- */
1138
- CC_PERCENT_FEE: number;
1139
- /**
1140
- * Minimum TakeProfit distance from priceOpen (percentage)
1141
- * Must be greater than (slippage + fees) to ensure profitable trades
1142
- *
1143
- * Calculation:
1144
- * - Slippage effect: ~0.2% (0.1% × 2 transactions)
1145
- * - Fees: 0.2% (0.1% × 2 transactions)
1146
- * - Minimum profit buffer: 0.1%
1147
- * - Total: 0.5%
1148
- *
1149
- * Default: 0.5% (covers all costs + minimum profit margin)
1150
- */
1151
- CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
1152
- /**
1153
- * Minimum StopLoss distance from priceOpen (percentage)
1154
- * Prevents signals from being immediately stopped out due to price volatility
1155
- * Default: 0.5% (buffer to avoid instant stop loss on normal market fluctuations)
1156
- */
1157
- CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
1158
- /**
1159
- * Maximum StopLoss distance from priceOpen (percentage)
1160
- * Prevents catastrophic losses from extreme StopLoss values
1161
- * Default: 20% (one signal cannot lose more than 20% of position)
1162
- */
1163
- CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
1164
- /**
1165
- * Maximum signal lifetime in minutes
1166
- * Prevents eternal signals that block risk limits for weeks/months
1167
- * Default: 1440 minutes (1 day)
1168
- */
1169
- CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
1170
- /**
1171
- * Maximum time allowed for signal generation (in seconds).
1172
- * Prevents long-running or stuck signal generation routines from blocking
1173
- * execution or consuming resources indefinitely. If generation exceeds this
1174
- * threshold the attempt should be aborted, logged and optionally retried.
1175
- *
1176
- * Default: 180 seconds (3 minutes)
1177
- */
1178
- CC_MAX_SIGNAL_GENERATION_SECONDS: number;
1179
- /**
1180
- * Number of retries for getCandles function
1181
- * Default: 3 retries
1182
- */
1183
- CC_GET_CANDLES_RETRY_COUNT: number;
1184
- /**
1185
- * Delay between retries for getCandles function (in milliseconds)
1186
- * Default: 5000 ms (5 seconds)
1187
- */
1188
- CC_GET_CANDLES_RETRY_DELAY_MS: number;
1189
- /**
1190
- * Maximum allowed deviation factor for price anomaly detection.
1191
- * Price should not be more than this factor lower than reference price.
1192
- *
1193
- * Reasoning:
1194
- * - Incomplete candles from Binance API typically have prices near 0 (e.g., $0.01-1)
1195
- * - Normal BTC price ranges: $20,000-100,000
1196
- * - Factor 1000 catches prices below $20-100 when median is $20,000-100,000
1197
- * - Factor 100 would be too permissive (allows $200 when median is $20,000)
1198
- * - Factor 10000 might be too strict for low-cap altcoins
1199
- *
1200
- * Example: BTC at $50,000 median → threshold $50 (catches $0.01-1 anomalies)
1201
- */
1202
- CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
1203
- /**
1204
- * Minimum number of candles required for reliable median calculation.
1205
- * Below this threshold, use simple average instead of median.
1206
- *
1207
- * Reasoning:
1208
- * - Each candle provides 4 price points (OHLC)
1209
- * - 5 candles = 20 price points, sufficient for robust median calculation
1210
- * - Below 5 candles, single anomaly can heavily skew median
1211
- * - Statistical rule of thumb: minimum 7-10 data points for median stability
1212
- * - Average is more stable than median for small datasets (n < 20)
1213
- *
1214
- * Example: 3 candles = 12 points (use average), 5 candles = 20 points (use median)
1215
- */
1216
- CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
1217
- /**
1218
- * Controls visibility of signal notes in markdown report tables.
1219
- * When enabled, the "Note" column will be displayed in all markdown reports
1220
- * (backtest, live, schedule, risk, etc.)
1221
- *
1222
- * Default: false (notes are hidden to reduce table width and improve readability)
1223
- */
1224
- CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
1225
- };
1226
- /**
1227
- * Type for global configuration object.
1228
- */
1229
- type GlobalConfig = typeof GLOBAL_CONFIG;
1230
-
1231
- /**
1232
- * Mapping of available table/markdown reports to their column definitions.
1233
- *
1234
- * Each property references a column definition object imported from
1235
- * `src/assets/*.columns`. These are used by markdown/report generators
1236
- * (backtest, live, schedule, risk, heat, performance, partial, walker).
1237
- */
1238
- declare const COLUMN_CONFIG: {
1239
- /** Columns used in backtest markdown tables and reports */
1240
- backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
1241
- /** Columns used by heatmap / heat reports */
1242
- heat_columns: ColumnModel<IHeatmapRow>[];
1243
- /** Columns for live trading reports and logs */
1244
- live_columns: ColumnModel<TickEvent>[];
1245
- /** Columns for partial-results / incremental reports */
1246
- partial_columns: ColumnModel<PartialEvent>[];
1247
- /** Columns for performance summary reports */
1248
- performance_columns: ColumnModel<MetricStats>[];
1249
- /** Columns for risk-related reports */
1250
- risk_columns: ColumnModel<RiskEvent>[];
1251
- /** Columns for scheduled report output */
1252
- schedule_columns: ColumnModel<ScheduledEvent>[];
1253
- /** Walker: PnL summary columns */
1254
- walker_pnl_columns: ColumnModel<SignalData$1>[];
1255
- /** Walker: strategy-level summary columns */
1256
- walker_strategy_columns: ColumnModel<IStrategyResult>[];
1257
- };
1258
- /**
1259
- * Type for the column configuration object.
1260
- */
1261
- type ColumnConfig = typeof COLUMN_CONFIG;
1262
-
1263
- /**
1264
- * Sets custom logger implementation for the framework.
1265
- *
1266
- * All log messages from internal services will be forwarded to the provided logger
1267
- * with automatic context injection (strategyName, exchangeName, symbol, etc.).
1268
- *
1269
- * @param logger - Custom logger implementing ILogger interface
1270
- *
1271
- * @example
1272
- * ```typescript
1273
- * setLogger({
1274
- * log: (topic, ...args) => console.log(topic, args),
1275
- * debug: (topic, ...args) => console.debug(topic, args),
1276
- * info: (topic, ...args) => console.info(topic, args),
1277
- * });
1278
- * ```
1279
- */
1280
- declare function setLogger(logger: ILogger): void;
1281
- /**
1282
- * Sets global configuration parameters for the framework.
1283
- * @param config - Partial configuration object to override default settings
1284
- * @param _unsafe - Skip config validations - required for testbed
1285
- *
1286
- * @example
1287
- * ```typescript
1288
- * setConfig({
1289
- * CC_SCHEDULE_AWAIT_MINUTES: 90,
1290
- * });
1291
- * ```
1292
- */
1293
- declare function setConfig(config: Partial<GlobalConfig>, _unsafe?: boolean): void;
1294
- /**
1295
- * Retrieves a copy of the current global configuration.
1296
- *
1297
- * Returns a shallow copy of the current GLOBAL_CONFIG to prevent accidental mutations.
1298
- * Use this to inspect the current configuration state without modifying it.
1299
- *
1300
- * @returns {GlobalConfig} A copy of the current global configuration object
1301
- *
1302
- * @example
1303
- * ```typescript
1304
- * const currentConfig = getConfig();
1305
- * console.log(currentConfig.CC_SCHEDULE_AWAIT_MINUTES);
1306
- * ```
1307
- */
1308
- declare function getConfig(): {
1309
- CC_SCHEDULE_AWAIT_MINUTES: number;
1310
- CC_AVG_PRICE_CANDLES_COUNT: number;
1311
- CC_PERCENT_SLIPPAGE: number;
1312
- CC_PERCENT_FEE: number;
1313
- CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
1314
- CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
1315
- CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
1316
- CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
1317
- CC_MAX_SIGNAL_GENERATION_SECONDS: number;
1318
- CC_GET_CANDLES_RETRY_COUNT: number;
1319
- CC_GET_CANDLES_RETRY_DELAY_MS: number;
1320
- CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
1321
- CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
1322
- CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
1323
- };
1324
- /**
1325
- * Retrieves the default configuration object for the framework.
1326
- *
1327
- * Returns a reference to the default configuration with all preset values.
1328
- * Use this to see what configuration options are available and their default values.
1329
- *
1330
- * @returns {GlobalConfig} The default configuration object
1331
- *
1332
- * @example
1333
- * ```typescript
1334
- * const defaultConfig = getDefaultConfig();
1335
- * console.log(defaultConfig.CC_SCHEDULE_AWAIT_MINUTES);
1336
- * ```
1337
- */
1338
- declare function getDefaultConfig(): Readonly<{
1339
- CC_SCHEDULE_AWAIT_MINUTES: number;
1340
- CC_AVG_PRICE_CANDLES_COUNT: number;
1341
- CC_PERCENT_SLIPPAGE: number;
1342
- CC_PERCENT_FEE: number;
1343
- CC_MIN_TAKEPROFIT_DISTANCE_PERCENT: number;
1344
- CC_MIN_STOPLOSS_DISTANCE_PERCENT: number;
1345
- CC_MAX_STOPLOSS_DISTANCE_PERCENT: number;
1346
- CC_MAX_SIGNAL_LIFETIME_MINUTES: number;
1347
- CC_MAX_SIGNAL_GENERATION_SECONDS: number;
1348
- CC_GET_CANDLES_RETRY_COUNT: number;
1349
- CC_GET_CANDLES_RETRY_DELAY_MS: number;
1350
- CC_GET_CANDLES_PRICE_ANOMALY_THRESHOLD_FACTOR: number;
1351
- CC_GET_CANDLES_MIN_CANDLES_FOR_MEDIAN: number;
1352
- CC_REPORT_SHOW_SIGNAL_NOTE: boolean;
1353
- }>;
1216
+ * Discriminated union of all tick results.
1217
+ * Use type guards: `result.action === "closed"` for type safety.
1218
+ */
1219
+ type IStrategyTickResult = IStrategyTickResultIdle | IStrategyTickResultScheduled | IStrategyTickResultOpened | IStrategyTickResultActive | IStrategyTickResultClosed | IStrategyTickResultCancelled;
1354
1220
  /**
1355
- * Sets custom column configurations for markdown report generation.
1356
- *
1357
- * Allows overriding default column definitions for any report type.
1358
- * All columns are validated before assignment to ensure structural correctness.
1221
+ * Backtest returns closed result (TP/SL or time_expired) or cancelled result (scheduled signal never activated).
1222
+ */
1223
+ type IStrategyBacktestResult = IStrategyTickResultClosed | IStrategyTickResultCancelled;
1224
+ /**
1225
+ * Unique strategy identifier.
1226
+ */
1227
+ type StrategyName = string;
1228
+
1229
+ /**
1230
+ * Statistical data calculated from backtest results.
1359
1231
  *
1360
- * @param columns - Partial column configuration object to override default column settings
1361
- * @param _unsafe - Skip column validations - required for testbed
1232
+ * All numeric values are null if calculation is unsafe (NaN, Infinity, etc).
1233
+ * Provides comprehensive metrics for strategy performance analysis.
1362
1234
  *
1363
1235
  * @example
1364
1236
  * ```typescript
1365
- * setColumns({
1366
- * backtest_columns: [
1367
- * {
1368
- * key: "customId",
1369
- * label: "Custom ID",
1370
- * format: (data) => data.signal.id,
1371
- * isVisible: () => true
1372
- * }
1373
- * ],
1237
+ * const stats = await Backtest.getData("my-strategy");
1238
+ *
1239
+ * console.log(`Total signals: ${stats.totalSignals}`);
1240
+ * console.log(`Win rate: ${stats.winRate}%`);
1241
+ * console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
1242
+ *
1243
+ * // Access raw signal data
1244
+ * stats.signalList.forEach(signal => {
1245
+ * console.log(`Signal ${signal.signal.id}: ${signal.pnl.pnlPercentage}%`);
1374
1246
  * });
1375
1247
  * ```
1376
- *
1377
- * @throws {Error} If column configuration is invalid
1378
1248
  */
1379
- declare function setColumns(columns: Partial<ColumnConfig>, _unsafe?: boolean): void;
1249
+ interface BacktestStatisticsModel {
1250
+ /** Array of all closed signals with full details (price, PNL, timestamps, etc.) */
1251
+ signalList: IStrategyTickResultClosed[];
1252
+ /** Total number of closed signals */
1253
+ totalSignals: number;
1254
+ /** Number of winning signals (PNL > 0) */
1255
+ winCount: number;
1256
+ /** Number of losing signals (PNL < 0) */
1257
+ lossCount: number;
1258
+ /** Win rate as percentage (0-100), null if unsafe. Higher is better. */
1259
+ winRate: number | null;
1260
+ /** Average PNL per signal as percentage, null if unsafe. Higher is better. */
1261
+ avgPnl: number | null;
1262
+ /** Cumulative PNL across all signals as percentage, null if unsafe. Higher is better. */
1263
+ totalPnl: number | null;
1264
+ /** Standard deviation of returns (volatility metric), null if unsafe. Lower is better. */
1265
+ stdDev: number | null;
1266
+ /** Sharpe Ratio (risk-adjusted return = avgPnl / stdDev), null if unsafe. Higher is better. */
1267
+ sharpeRatio: number | null;
1268
+ /** Annualized Sharpe Ratio (sharpeRatio × √365), null if unsafe. Higher is better. */
1269
+ annualizedSharpeRatio: number | null;
1270
+ /** Certainty Ratio (avgWin / |avgLoss|), null if unsafe. Higher is better. */
1271
+ certaintyRatio: number | null;
1272
+ /** Expected yearly returns based on average trade duration and PNL, null if unsafe. Higher is better. */
1273
+ expectedYearlyReturns: number | null;
1274
+ }
1275
+
1380
1276
  /**
1381
- * Retrieves a copy of the current column configuration for markdown report generation.
1382
- *
1383
- * Returns a shallow copy of the current COLUMN_CONFIG to prevent accidental mutations.
1384
- * Use this to inspect the current column definitions without modifying them.
1277
+ * Contract for walker completion events.
1385
1278
  *
1386
- * @returns {ColumnConfig} A copy of the current column configuration object
1279
+ * Emitted when all strategies have been tested and final results are available.
1280
+ * Contains complete results of the walker comparison including the best strategy.
1387
1281
  *
1388
1282
  * @example
1389
1283
  * ```typescript
1390
- * const currentColumns = getColumns();
1391
- * console.log(currentColumns.backtest_columns.length);
1284
+ * import { walkerCompleteSubject } from "backtest-kit";
1285
+ *
1286
+ * walkerCompleteSubject
1287
+ * .filter((event) => event.symbol === "BTCUSDT")
1288
+ * .connect((event) => {
1289
+ * console.log("Walker completed:", event.walkerName);
1290
+ * console.log("Best strategy:", event.bestStrategy);
1291
+ * console.log("Best metric:", event.bestMetric);
1292
+ * });
1392
1293
  * ```
1393
1294
  */
1394
- declare function getColumns(): {
1395
- backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
1396
- heat_columns: ColumnModel<IHeatmapRow>[];
1397
- live_columns: ColumnModel<TickEvent>[];
1398
- partial_columns: ColumnModel<PartialEvent>[];
1399
- performance_columns: ColumnModel<MetricStats>[];
1400
- risk_columns: ColumnModel<RiskEvent>[];
1401
- schedule_columns: ColumnModel<ScheduledEvent>[];
1402
- walker_pnl_columns: ColumnModel<SignalData$1>[];
1403
- walker_strategy_columns: ColumnModel<IStrategyResult>[];
1404
- };
1295
+ interface WalkerCompleteContract {
1296
+ /** walkerName - Walker name */
1297
+ walkerName: WalkerName;
1298
+ /** symbol - Symbol tested */
1299
+ symbol: string;
1300
+ /** exchangeName - Exchange used */
1301
+ exchangeName: ExchangeName;
1302
+ /** frameName - Frame used */
1303
+ frameName: FrameName;
1304
+ /** metric - Metric used for optimization */
1305
+ metric: WalkerMetric;
1306
+ /** totalStrategies - Total number of strategies tested */
1307
+ totalStrategies: number;
1308
+ /** bestStrategy - Best performing strategy name */
1309
+ bestStrategy: StrategyName | null;
1310
+ /** bestMetric - Best metric value achieved */
1311
+ bestMetric: number | null;
1312
+ /** bestStats - Best strategy statistics */
1313
+ bestStats: BacktestStatisticsModel | null;
1314
+ }
1315
+
1405
1316
  /**
1406
- * Retrieves the default column configuration object for markdown report generation.
1407
- *
1408
- * Returns a reference to the default column definitions with all preset values.
1409
- * Use this to see what column options are available and their default definitions.
1410
- *
1411
- * @returns {ColumnConfig} The default column configuration object
1412
- *
1413
- * @example
1414
- * ```typescript
1415
- * const defaultColumns = getDefaultColumns();
1416
- * console.log(defaultColumns.backtest_columns);
1417
- * ```
1317
+ * Optimization metric for comparing strategies.
1318
+ * Higher values are always better (metric is maximized).
1418
1319
  */
1419
- declare function getDefaultColumns(): Readonly<{
1420
- backtest_columns: ColumnModel<IStrategyTickResultClosed>[];
1421
- heat_columns: ColumnModel<IHeatmapRow>[];
1422
- live_columns: ColumnModel<TickEvent>[];
1423
- partial_columns: ColumnModel<PartialEvent>[];
1424
- performance_columns: ColumnModel<MetricStats>[];
1425
- risk_columns: ColumnModel<RiskEvent>[];
1426
- schedule_columns: ColumnModel<ScheduledEvent>[];
1427
- walker_pnl_columns: ColumnModel<SignalData$1>[];
1428
- walker_strategy_columns: ColumnModel<IStrategyResult>[];
1429
- }>;
1320
+ type WalkerMetric = "sharpeRatio" | "annualizedSharpeRatio" | "winRate" | "totalPnl" | "certaintyRatio" | "avgPnl" | "expectedYearlyReturns";
1321
+ /**
1322
+ * Walker schema registered via addWalker().
1323
+ * Defines A/B testing configuration for multiple strategies.
1324
+ */
1325
+ interface IWalkerSchema {
1326
+ /** Unique walker identifier for registration */
1327
+ walkerName: WalkerName;
1328
+ /** Optional developer note for documentation */
1329
+ note?: string;
1330
+ /** Exchange to use for backtesting all strategies */
1331
+ exchangeName: ExchangeName;
1332
+ /** Timeframe generator to use for backtesting all strategies */
1333
+ frameName: FrameName;
1334
+ /** List of strategy names to compare (must be registered via addStrategy) */
1335
+ strategies: StrategyName[];
1336
+ /** Metric to optimize (default: "sharpeRatio") */
1337
+ metric?: WalkerMetric;
1338
+ /** Optional lifecycle event callbacks */
1339
+ callbacks?: Partial<IWalkerCallbacks>;
1340
+ }
1341
+ /**
1342
+ * Optional lifecycle callbacks for walker events.
1343
+ * Called during strategy comparison process.
1344
+ */
1345
+ interface IWalkerCallbacks {
1346
+ /** Called when starting to test a specific strategy */
1347
+ onStrategyStart: (strategyName: StrategyName, symbol: string) => void;
1348
+ /** Called when a strategy backtest completes */
1349
+ onStrategyComplete: (strategyName: StrategyName, symbol: string, stats: BacktestStatisticsModel, metric: number | null) => void;
1350
+ /** Called when a strategy backtest fails with an error */
1351
+ onStrategyError: (strategyName: StrategyName, symbol: string, error: Error | unknown) => void;
1352
+ /** Called when all strategies have been tested */
1353
+ onComplete: (results: IWalkerResults) => void;
1354
+ }
1355
+ /**
1356
+ * Result for a single strategy in the comparison.
1357
+ */
1358
+ interface IWalkerStrategyResult {
1359
+ /** Strategy name */
1360
+ strategyName: StrategyName;
1361
+ /** Backtest statistics for this strategy */
1362
+ stats: BacktestStatisticsModel;
1363
+ /** Metric value used for comparison (null if invalid) */
1364
+ metric: number | null;
1365
+ /** Rank position (1 = best, 2 = second best, etc.) */
1366
+ rank: number;
1367
+ }
1368
+ /**
1369
+ * Complete walker results after comparing all strategies.
1370
+ */
1371
+ interface IWalkerResults extends WalkerCompleteContract {
1372
+ /** Symbol tested */
1373
+ symbol: string;
1374
+ /** Exchange used */
1375
+ exchangeName: ExchangeName;
1376
+ /** Walker name */
1377
+ walkerName: WalkerName;
1378
+ /** Frame used */
1379
+ frameName: FrameName;
1380
+ }
1381
+ /**
1382
+ * Unique walker identifier.
1383
+ */
1384
+ type WalkerName = string;
1430
1385
 
1431
1386
  /**
1432
1387
  * Base parameters common to all sizing calculations.
@@ -4364,6 +4319,51 @@ interface PerformanceStatisticsModel {
4364
4319
  events: PerformanceContract[];
4365
4320
  }
4366
4321
 
4322
+ /**
4323
+ * Signal data for PNL table.
4324
+ * Represents a single closed signal with essential trading information.
4325
+ */
4326
+ interface SignalData$1 {
4327
+ /** Strategy that generated this signal */
4328
+ strategyName: StrategyName;
4329
+ /** Unique signal identifier */
4330
+ signalId: string;
4331
+ /** Trading pair symbol */
4332
+ symbol: string;
4333
+ /** Position type (long/short) */
4334
+ position: string;
4335
+ /** PNL as percentage */
4336
+ pnl: number;
4337
+ /** Reason why signal was closed */
4338
+ closeReason: string;
4339
+ /** Timestamp when signal opened */
4340
+ openTime: number;
4341
+ /** Timestamp when signal closed */
4342
+ closeTime: number;
4343
+ }
4344
+ /**
4345
+ * Strategy result entry for comparison table.
4346
+ * Contains strategy name, full statistics, and metric value for ranking.
4347
+ */
4348
+ interface IStrategyResult {
4349
+ /** Strategy name */
4350
+ strategyName: StrategyName;
4351
+ /** Complete backtest statistics for this strategy */
4352
+ stats: BacktestStatisticsModel;
4353
+ /** Value of the optimization metric (null if invalid) */
4354
+ metricValue: number | null;
4355
+ }
4356
+ /**
4357
+ * Alias for walker statistics result interface.
4358
+ * Used for clarity in markdown service context.
4359
+ *
4360
+ * Extends IWalkerResults with additional strategy comparison data.
4361
+ */
4362
+ interface WalkerStatisticsModel extends WalkerCompleteContract {
4363
+ /** Array of all strategy results for comparison and analysis */
4364
+ strategyResults: IStrategyResult[];
4365
+ }
4366
+
4367
4367
  /**
4368
4368
  * Unified partial profit/loss event data for report generation.
4369
4369
  * Contains all information about profit and loss level milestones.
@@ -10778,4 +10778,4 @@ declare const backtest: {
10778
10778
  loggerService: LoggerService;
10779
10779
  };
10780
10780
 
10781
- export { Backtest, type BacktestStatisticsModel, Cache, type CandleInterval, type ColumnConfig, type ColumnModel, Constant, type DoneContract, type EntityId, Exchange, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type HeatmapStatisticsModel, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategyResult, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatisticsModel, type MessageModel, type MessageRole, MethodContextService, type MetricStats, Optimizer, Partial$1 as Partial, type PartialData, type PartialEvent, type PartialLossContract, type PartialProfitContract, type PartialStatisticsModel, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatisticsModel, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, Risk, type RiskContract, type RiskData, type RiskEvent, type RiskStatisticsModel, Schedule, type ScheduleData, type ScheduleStatisticsModel, type ScheduledEvent, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, type TickEvent, Walker, type WalkerCompleteContract, type WalkerContract, type WalkerMetric, type WalkerStatisticsModel, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getColumns, getConfig, getDate, getDefaultColumns, getDefaultConfig, getMode, hasTradeContext, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenRisk, listenRiskOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setColumns, setConfig, setLogger };
10781
+ export { Backtest, type BacktestStatisticsModel, Cache, type CandleInterval, type ColumnConfig, type ColumnModel, Constant, type DoneContract, type EntityId, Exchange, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type HeatmapStatisticsModel, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategyResult, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatisticsModel, type MessageModel, type MessageRole, MethodContextService, type MetricStats, Optimizer, Partial$1 as Partial, type PartialData, type PartialEvent, type PartialLossContract, type PartialProfitContract, type PartialStatisticsModel, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatisticsModel, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, Risk, type RiskContract, type RiskData, type RiskEvent, type RiskStatisticsModel, Schedule, type ScheduleData, type ScheduleStatisticsModel, type ScheduledEvent, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, type TickEvent, Walker, type WalkerCompleteContract, type WalkerContract, type WalkerMetric, type SignalData$1 as WalkerSignalData, type WalkerStatisticsModel, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getColumns, getConfig, getDate, getDefaultColumns, getDefaultConfig, getMode, hasTradeContext, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenRisk, listenRiskOnce, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setColumns, setConfig, setLogger };