backtest-kit 1.1.8 → 1.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +806 -970
- package/build/index.cjs +3588 -275
- package/build/index.mjs +3569 -275
- package/package.json +1 -1
- package/types.d.ts +2955 -520
package/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as di_scoped from 'di-scoped';
|
|
2
2
|
import * as functools_kit from 'functools-kit';
|
|
3
|
+
import { Subject } from 'functools-kit';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Interface representing a logging mechanism for the swarm system.
|
|
@@ -353,6 +354,137 @@ declare const MethodContextService: (new () => {
|
|
|
353
354
|
};
|
|
354
355
|
}, "prototype"> & di_scoped.IScopedClassRun<[context: IMethodContext]>;
|
|
355
356
|
|
|
357
|
+
/**
|
|
358
|
+
* Risk check arguments for evaluating whether to allow opening a new position.
|
|
359
|
+
* Called BEFORE signal creation to validate if conditions allow new signals.
|
|
360
|
+
* Contains only passthrough arguments from ClientStrategy context.
|
|
361
|
+
*/
|
|
362
|
+
interface IRiskCheckArgs {
|
|
363
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
364
|
+
symbol: string;
|
|
365
|
+
/** Strategy name requesting to open a position */
|
|
366
|
+
strategyName: StrategyName;
|
|
367
|
+
/** Exchange name */
|
|
368
|
+
exchangeName: ExchangeName;
|
|
369
|
+
/** Current VWAP price */
|
|
370
|
+
currentPrice: number;
|
|
371
|
+
/** Current timestamp */
|
|
372
|
+
timestamp: number;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Active position tracked by ClientRisk for cross-strategy analysis.
|
|
376
|
+
*/
|
|
377
|
+
interface IRiskActivePosition {
|
|
378
|
+
/** Signal details for the active position */
|
|
379
|
+
signal: ISignalRow;
|
|
380
|
+
/** Strategy name owning the position */
|
|
381
|
+
strategyName: string;
|
|
382
|
+
/** Exchange name */
|
|
383
|
+
exchangeName: string;
|
|
384
|
+
/** Timestamp when the position was opened */
|
|
385
|
+
openTimestamp: number;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Optional callbacks for risk events.
|
|
389
|
+
*/
|
|
390
|
+
interface IRiskCallbacks {
|
|
391
|
+
/** Called when a signal is rejected due to risk limits */
|
|
392
|
+
onRejected: (symbol: string, params: IRiskCheckArgs) => void;
|
|
393
|
+
/** Called when a signal passes risk checks */
|
|
394
|
+
onAllowed: (symbol: string, params: IRiskCheckArgs) => void;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Payload passed to risk validation functions.
|
|
398
|
+
* Extends IRiskCheckArgs with portfolio state data.
|
|
399
|
+
*/
|
|
400
|
+
interface IRiskValidationPayload extends IRiskCheckArgs {
|
|
401
|
+
/** Number of currently active positions across all strategies */
|
|
402
|
+
activePositionCount: number;
|
|
403
|
+
/** List of currently active positions across all strategies */
|
|
404
|
+
activePositions: IRiskActivePosition[];
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Risk validation function type.
|
|
408
|
+
* Validates risk parameters and throws error if validation fails.
|
|
409
|
+
*/
|
|
410
|
+
interface IRiskValidationFn {
|
|
411
|
+
(payload: IRiskValidationPayload): void | Promise<void>;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Risk validation configuration.
|
|
415
|
+
* Defines validation logic with optional documentation.
|
|
416
|
+
*/
|
|
417
|
+
interface IRiskValidation {
|
|
418
|
+
/**
|
|
419
|
+
* The validation function to apply to the risk check parameters.
|
|
420
|
+
*/
|
|
421
|
+
validate: IRiskValidationFn;
|
|
422
|
+
/**
|
|
423
|
+
* Optional description for documentation purposes.
|
|
424
|
+
* Aids in understanding the purpose or behavior of the validation.
|
|
425
|
+
*/
|
|
426
|
+
note?: string;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Risk schema registered via addRisk().
|
|
430
|
+
* Defines portfolio-level risk controls via custom validations.
|
|
431
|
+
*/
|
|
432
|
+
interface IRiskSchema {
|
|
433
|
+
/** Unique risk profile identifier */
|
|
434
|
+
riskName: RiskName;
|
|
435
|
+
/** Optional developer note for documentation */
|
|
436
|
+
note?: string;
|
|
437
|
+
/** Optional lifecycle event callbacks (onRejected, onAllowed) */
|
|
438
|
+
callbacks?: Partial<IRiskCallbacks>;
|
|
439
|
+
/** Custom validations array for risk logic */
|
|
440
|
+
validations: (IRiskValidation | IRiskValidationFn)[];
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Risk parameters passed to ClientRisk constructor.
|
|
444
|
+
* Combines schema with runtime dependencies.
|
|
445
|
+
*/
|
|
446
|
+
interface IRiskParams extends IRiskSchema {
|
|
447
|
+
/** Logger service for debug output */
|
|
448
|
+
logger: ILogger;
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Risk interface implemented by ClientRisk.
|
|
452
|
+
* Provides risk checking for signals and position tracking.
|
|
453
|
+
*/
|
|
454
|
+
interface IRisk {
|
|
455
|
+
/**
|
|
456
|
+
* Check if a signal should be allowed based on risk limits.
|
|
457
|
+
*
|
|
458
|
+
* @param params - Risk check arguments (position size, portfolio state, etc.)
|
|
459
|
+
* @returns Promise resolving to risk check result
|
|
460
|
+
*/
|
|
461
|
+
checkSignal: (params: IRiskCheckArgs) => Promise<boolean>;
|
|
462
|
+
/**
|
|
463
|
+
* Register a new opened signal/position.
|
|
464
|
+
*
|
|
465
|
+
* @param symbol - Trading pair symbol
|
|
466
|
+
* @param context - Context information (strategyName, riskName)
|
|
467
|
+
*/
|
|
468
|
+
addSignal: (symbol: string, context: {
|
|
469
|
+
strategyName: string;
|
|
470
|
+
riskName: string;
|
|
471
|
+
}) => Promise<void>;
|
|
472
|
+
/**
|
|
473
|
+
* Remove a closed signal/position.
|
|
474
|
+
*
|
|
475
|
+
* @param symbol - Trading pair symbol
|
|
476
|
+
* @param context - Context information (strategyName, riskName)
|
|
477
|
+
*/
|
|
478
|
+
removeSignal: (symbol: string, context: {
|
|
479
|
+
strategyName: string;
|
|
480
|
+
riskName: string;
|
|
481
|
+
}) => Promise<void>;
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Unique risk profile identifier.
|
|
485
|
+
*/
|
|
486
|
+
type RiskName = string;
|
|
487
|
+
|
|
356
488
|
/**
|
|
357
489
|
* Signal generation interval for throttling.
|
|
358
490
|
* Enforces minimum time between getSignal calls.
|
|
@@ -427,6 +559,8 @@ interface IStrategySchema {
|
|
|
427
559
|
getSignal: (symbol: string) => Promise<ISignalDto | null>;
|
|
428
560
|
/** Optional lifecycle event callbacks (onOpen, onClose) */
|
|
429
561
|
callbacks?: Partial<IStrategyCallbacks>;
|
|
562
|
+
/** Optional risk profile identifier for risk management */
|
|
563
|
+
riskName?: RiskName;
|
|
430
564
|
}
|
|
431
565
|
/**
|
|
432
566
|
* Reason why signal was closed.
|
|
@@ -457,6 +591,8 @@ interface IStrategyTickResultIdle {
|
|
|
457
591
|
strategyName: StrategyName;
|
|
458
592
|
/** Exchange name for tracking idle events */
|
|
459
593
|
exchangeName: ExchangeName;
|
|
594
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
595
|
+
symbol: string;
|
|
460
596
|
/** Current VWAP price during idle state */
|
|
461
597
|
currentPrice: number;
|
|
462
598
|
}
|
|
@@ -473,6 +609,8 @@ interface IStrategyTickResultOpened {
|
|
|
473
609
|
strategyName: StrategyName;
|
|
474
610
|
/** Exchange name for tracking */
|
|
475
611
|
exchangeName: ExchangeName;
|
|
612
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
613
|
+
symbol: string;
|
|
476
614
|
/** Current VWAP price at signal open */
|
|
477
615
|
currentPrice: number;
|
|
478
616
|
}
|
|
@@ -491,6 +629,8 @@ interface IStrategyTickResultActive {
|
|
|
491
629
|
strategyName: StrategyName;
|
|
492
630
|
/** Exchange name for tracking */
|
|
493
631
|
exchangeName: ExchangeName;
|
|
632
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
633
|
+
symbol: string;
|
|
494
634
|
}
|
|
495
635
|
/**
|
|
496
636
|
* Tick result: signal closed with PNL.
|
|
@@ -513,6 +653,8 @@ interface IStrategyTickResultClosed {
|
|
|
513
653
|
strategyName: StrategyName;
|
|
514
654
|
/** Exchange name for tracking */
|
|
515
655
|
exchangeName: ExchangeName;
|
|
656
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
657
|
+
symbol: string;
|
|
516
658
|
}
|
|
517
659
|
/**
|
|
518
660
|
* Discriminated union of all tick results.
|
|
@@ -572,162 +714,776 @@ interface IStrategy {
|
|
|
572
714
|
type StrategyName = string;
|
|
573
715
|
|
|
574
716
|
/**
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
* The strategy will be validated for:
|
|
578
|
-
* - Signal validation (prices, TP/SL logic, timestamps)
|
|
579
|
-
* - Interval throttling (prevents signal spam)
|
|
580
|
-
* - Crash-safe persistence in live mode
|
|
581
|
-
*
|
|
582
|
-
* @param strategySchema - Strategy configuration object
|
|
583
|
-
* @param strategySchema.strategyName - Unique strategy identifier
|
|
584
|
-
* @param strategySchema.interval - Signal generation interval ("1m" | "3m" | "5m" | "15m" | "30m" | "1h")
|
|
585
|
-
* @param strategySchema.getSignal - Async function that generates trading signals
|
|
586
|
-
* @param strategySchema.callbacks - Optional lifecycle callbacks (onOpen, onClose)
|
|
587
|
-
*
|
|
588
|
-
* @example
|
|
589
|
-
* ```typescript
|
|
590
|
-
* addStrategy({
|
|
591
|
-
* strategyName: "my-strategy",
|
|
592
|
-
* interval: "5m",
|
|
593
|
-
* getSignal: async (symbol) => ({
|
|
594
|
-
* position: "long",
|
|
595
|
-
* priceOpen: 50000,
|
|
596
|
-
* priceTakeProfit: 51000,
|
|
597
|
-
* priceStopLoss: 49000,
|
|
598
|
-
* minuteEstimatedTime: 60,
|
|
599
|
-
* timestamp: Date.now(),
|
|
600
|
-
* }),
|
|
601
|
-
* callbacks: {
|
|
602
|
-
* onOpen: (symbol, signal, currentPrice, backtest) => console.log("Signal opened"),
|
|
603
|
-
* onClose: (symbol, signal, priceClose, backtest) => console.log("Signal closed"),
|
|
604
|
-
* },
|
|
605
|
-
* });
|
|
606
|
-
* ```
|
|
607
|
-
*/
|
|
608
|
-
declare function addStrategy(strategySchema: IStrategySchema): void;
|
|
609
|
-
/**
|
|
610
|
-
* Registers an exchange data source in the framework.
|
|
611
|
-
*
|
|
612
|
-
* The exchange provides:
|
|
613
|
-
* - Historical candle data via getCandles
|
|
614
|
-
* - Price/quantity formatting for the exchange
|
|
615
|
-
* - VWAP calculation from last 5 1m candles
|
|
616
|
-
*
|
|
617
|
-
* @param exchangeSchema - Exchange configuration object
|
|
618
|
-
* @param exchangeSchema.exchangeName - Unique exchange identifier
|
|
619
|
-
* @param exchangeSchema.getCandles - Async function to fetch candle data
|
|
620
|
-
* @param exchangeSchema.formatPrice - Async function to format prices
|
|
621
|
-
* @param exchangeSchema.formatQuantity - Async function to format quantities
|
|
622
|
-
* @param exchangeSchema.callbacks - Optional callback for candle data events
|
|
623
|
-
*
|
|
624
|
-
* @example
|
|
625
|
-
* ```typescript
|
|
626
|
-
* addExchange({
|
|
627
|
-
* exchangeName: "binance",
|
|
628
|
-
* getCandles: async (symbol, interval, since, limit) => {
|
|
629
|
-
* // Fetch from Binance API or database
|
|
630
|
-
* return [{
|
|
631
|
-
* timestamp: Date.now(),
|
|
632
|
-
* open: 50000,
|
|
633
|
-
* high: 51000,
|
|
634
|
-
* low: 49000,
|
|
635
|
-
* close: 50500,
|
|
636
|
-
* volume: 1000,
|
|
637
|
-
* }];
|
|
638
|
-
* },
|
|
639
|
-
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
640
|
-
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
641
|
-
* });
|
|
642
|
-
* ```
|
|
643
|
-
*/
|
|
644
|
-
declare function addExchange(exchangeSchema: IExchangeSchema): void;
|
|
645
|
-
/**
|
|
646
|
-
* Registers a timeframe generator for backtesting.
|
|
647
|
-
*
|
|
648
|
-
* The frame defines:
|
|
649
|
-
* - Start and end dates for backtest period
|
|
650
|
-
* - Interval for timeframe generation
|
|
651
|
-
* - Callback for timeframe generation events
|
|
717
|
+
* Statistical data calculated from backtest results.
|
|
652
718
|
*
|
|
653
|
-
*
|
|
654
|
-
*
|
|
655
|
-
* @param frameSchema.interval - Timeframe interval ("1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "8h" | "12h" | "1d" | "3d")
|
|
656
|
-
* @param frameSchema.startDate - Start date for timeframe generation
|
|
657
|
-
* @param frameSchema.endDate - End date for timeframe generation
|
|
658
|
-
* @param frameSchema.callbacks - Optional callback for timeframe events
|
|
719
|
+
* All numeric values are null if calculation is unsafe (NaN, Infinity, etc).
|
|
720
|
+
* Provides comprehensive metrics for strategy performance analysis.
|
|
659
721
|
*
|
|
660
722
|
* @example
|
|
661
723
|
* ```typescript
|
|
662
|
-
*
|
|
663
|
-
* frameName: "1d-backtest",
|
|
664
|
-
* interval: "1m",
|
|
665
|
-
* startDate: new Date("2024-01-01T00:00:00Z"),
|
|
666
|
-
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
667
|
-
* callbacks: {
|
|
668
|
-
* onTimeframe: (timeframe, startDate, endDate, interval) => {
|
|
669
|
-
* console.log(`Generated ${timeframe.length} timeframes`);
|
|
670
|
-
* },
|
|
671
|
-
* },
|
|
672
|
-
* });
|
|
673
|
-
* ```
|
|
674
|
-
*/
|
|
675
|
-
declare function addFrame(frameSchema: IFrameSchema): void;
|
|
676
|
-
|
|
677
|
-
/**
|
|
678
|
-
* Returns a list of all registered exchange schemas.
|
|
679
|
-
*
|
|
680
|
-
* Retrieves all exchanges that have been registered via addExchange().
|
|
681
|
-
* Useful for debugging, documentation, or building dynamic UIs.
|
|
682
|
-
*
|
|
683
|
-
* @returns Array of exchange schemas with their configurations
|
|
724
|
+
* const stats = await Backtest.getData("my-strategy");
|
|
684
725
|
*
|
|
685
|
-
*
|
|
686
|
-
*
|
|
687
|
-
*
|
|
726
|
+
* console.log(`Total signals: ${stats.totalSignals}`);
|
|
727
|
+
* console.log(`Win rate: ${stats.winRate}%`);
|
|
728
|
+
* console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
|
|
688
729
|
*
|
|
689
|
-
*
|
|
690
|
-
*
|
|
691
|
-
*
|
|
692
|
-
* getCandles: async (symbol, interval, since, limit) => [...],
|
|
693
|
-
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
694
|
-
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
730
|
+
* // Access raw signal data
|
|
731
|
+
* stats.signalList.forEach(signal => {
|
|
732
|
+
* console.log(`Signal ${signal.signal.id}: ${signal.pnl.pnlPercentage}%`);
|
|
695
733
|
* });
|
|
696
|
-
*
|
|
697
|
-
* const exchanges = listExchanges();
|
|
698
|
-
* console.log(exchanges);
|
|
699
|
-
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
700
734
|
* ```
|
|
701
735
|
*/
|
|
702
|
-
|
|
736
|
+
interface BacktestStatistics {
|
|
737
|
+
/** Array of all closed signals with full details (price, PNL, timestamps, etc.) */
|
|
738
|
+
signalList: IStrategyTickResultClosed[];
|
|
739
|
+
/** Total number of closed signals */
|
|
740
|
+
totalSignals: number;
|
|
741
|
+
/** Number of winning signals (PNL > 0) */
|
|
742
|
+
winCount: number;
|
|
743
|
+
/** Number of losing signals (PNL < 0) */
|
|
744
|
+
lossCount: number;
|
|
745
|
+
/** Win rate as percentage (0-100), null if unsafe. Higher is better. */
|
|
746
|
+
winRate: number | null;
|
|
747
|
+
/** Average PNL per signal as percentage, null if unsafe. Higher is better. */
|
|
748
|
+
avgPnl: number | null;
|
|
749
|
+
/** Cumulative PNL across all signals as percentage, null if unsafe. Higher is better. */
|
|
750
|
+
totalPnl: number | null;
|
|
751
|
+
/** Standard deviation of returns (volatility metric), null if unsafe. Lower is better. */
|
|
752
|
+
stdDev: number | null;
|
|
753
|
+
/** Sharpe Ratio (risk-adjusted return = avgPnl / stdDev), null if unsafe. Higher is better. */
|
|
754
|
+
sharpeRatio: number | null;
|
|
755
|
+
/** Annualized Sharpe Ratio (sharpeRatio × √365), null if unsafe. Higher is better. */
|
|
756
|
+
annualizedSharpeRatio: number | null;
|
|
757
|
+
/** Certainty Ratio (avgWin / |avgLoss|), null if unsafe. Higher is better. */
|
|
758
|
+
certaintyRatio: number | null;
|
|
759
|
+
/** Expected yearly returns based on average trade duration and PNL, null if unsafe. Higher is better. */
|
|
760
|
+
expectedYearlyReturns: number | null;
|
|
761
|
+
}
|
|
703
762
|
/**
|
|
704
|
-
*
|
|
705
|
-
*
|
|
706
|
-
* Retrieves all strategies that have been registered via addStrategy().
|
|
707
|
-
* Useful for debugging, documentation, or building dynamic UIs.
|
|
763
|
+
* Service for generating and saving backtest markdown reports.
|
|
708
764
|
*
|
|
709
|
-
*
|
|
765
|
+
* Features:
|
|
766
|
+
* - Listens to signal events via onTick callback
|
|
767
|
+
* - Accumulates closed signals per strategy using memoized storage
|
|
768
|
+
* - Generates markdown tables with detailed signal information
|
|
769
|
+
* - Saves reports to disk in logs/backtest/{strategyName}.md
|
|
710
770
|
*
|
|
711
771
|
* @example
|
|
712
772
|
* ```typescript
|
|
713
|
-
*
|
|
773
|
+
* const service = new BacktestMarkdownService();
|
|
714
774
|
*
|
|
775
|
+
* // Add to strategy callbacks
|
|
715
776
|
* addStrategy({
|
|
716
777
|
* strategyName: "my-strategy",
|
|
717
|
-
*
|
|
718
|
-
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
*
|
|
722
|
-
* priceTakeProfit: 51000,
|
|
723
|
-
* priceStopLoss: 49000,
|
|
724
|
-
* minuteEstimatedTime: 60,
|
|
725
|
-
* }),
|
|
778
|
+
* callbacks: {
|
|
779
|
+
* onTick: (symbol, result, backtest) => {
|
|
780
|
+
* service.tick(result);
|
|
781
|
+
* }
|
|
782
|
+
* }
|
|
726
783
|
* });
|
|
727
784
|
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
785
|
+
* // After backtest, generate and save report
|
|
786
|
+
* await service.saveReport("my-strategy");
|
|
787
|
+
* ```
|
|
788
|
+
*/
|
|
789
|
+
declare class BacktestMarkdownService {
|
|
790
|
+
/** Logger service for debug output */
|
|
791
|
+
private readonly loggerService;
|
|
792
|
+
/**
|
|
793
|
+
* Memoized function to get or create ReportStorage for a strategy.
|
|
794
|
+
* Each strategy gets its own isolated storage instance.
|
|
795
|
+
*/
|
|
796
|
+
private getStorage;
|
|
797
|
+
/**
|
|
798
|
+
* Processes tick events and accumulates closed signals.
|
|
799
|
+
* Should be called from IStrategyCallbacks.onTick.
|
|
800
|
+
*
|
|
801
|
+
* Only processes closed signals - opened signals are ignored.
|
|
802
|
+
*
|
|
803
|
+
* @param data - Tick result from strategy execution (opened or closed)
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* ```typescript
|
|
807
|
+
* const service = new BacktestMarkdownService();
|
|
808
|
+
*
|
|
809
|
+
* callbacks: {
|
|
810
|
+
* onTick: (symbol, result, backtest) => {
|
|
811
|
+
* service.tick(result);
|
|
812
|
+
* }
|
|
813
|
+
* }
|
|
814
|
+
* ```
|
|
815
|
+
*/
|
|
816
|
+
private tick;
|
|
817
|
+
/**
|
|
818
|
+
* Gets statistical data from all closed signals for a strategy.
|
|
819
|
+
* Delegates to ReportStorage.getData().
|
|
820
|
+
*
|
|
821
|
+
* @param strategyName - Strategy name to get data for
|
|
822
|
+
* @returns Statistical data object with all metrics
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* ```typescript
|
|
826
|
+
* const service = new BacktestMarkdownService();
|
|
827
|
+
* const stats = await service.getData("my-strategy");
|
|
828
|
+
* console.log(stats.sharpeRatio, stats.winRate);
|
|
829
|
+
* ```
|
|
830
|
+
*/
|
|
831
|
+
getData: (strategyName: StrategyName) => Promise<BacktestStatistics>;
|
|
832
|
+
/**
|
|
833
|
+
* Generates markdown report with all closed signals for a strategy.
|
|
834
|
+
* Delegates to ReportStorage.generateReport().
|
|
835
|
+
*
|
|
836
|
+
* @param strategyName - Strategy name to generate report for
|
|
837
|
+
* @returns Markdown formatted report string with table of all closed signals
|
|
838
|
+
*
|
|
839
|
+
* @example
|
|
840
|
+
* ```typescript
|
|
841
|
+
* const service = new BacktestMarkdownService();
|
|
842
|
+
* const markdown = await service.getReport("my-strategy");
|
|
843
|
+
* console.log(markdown);
|
|
844
|
+
* ```
|
|
845
|
+
*/
|
|
846
|
+
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
847
|
+
/**
|
|
848
|
+
* Saves strategy report to disk.
|
|
849
|
+
* Creates directory if it doesn't exist.
|
|
850
|
+
* Delegates to ReportStorage.dump().
|
|
851
|
+
*
|
|
852
|
+
* @param strategyName - Strategy name to save report for
|
|
853
|
+
* @param path - Directory path to save report (default: "./logs/backtest")
|
|
854
|
+
*
|
|
855
|
+
* @example
|
|
856
|
+
* ```typescript
|
|
857
|
+
* const service = new BacktestMarkdownService();
|
|
858
|
+
*
|
|
859
|
+
* // Save to default path: ./logs/backtest/my-strategy.md
|
|
860
|
+
* await service.dump("my-strategy");
|
|
861
|
+
*
|
|
862
|
+
* // Save to custom path: ./custom/path/my-strategy.md
|
|
863
|
+
* await service.dump("my-strategy", "./custom/path");
|
|
864
|
+
* ```
|
|
865
|
+
*/
|
|
866
|
+
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
867
|
+
/**
|
|
868
|
+
* Clears accumulated signal data from storage.
|
|
869
|
+
* If strategyName is provided, clears only that strategy's data.
|
|
870
|
+
* If strategyName is omitted, clears all strategies' data.
|
|
871
|
+
*
|
|
872
|
+
* @param strategyName - Optional strategy name to clear specific strategy data
|
|
873
|
+
*
|
|
874
|
+
* @example
|
|
875
|
+
* ```typescript
|
|
876
|
+
* const service = new BacktestMarkdownService();
|
|
877
|
+
*
|
|
878
|
+
* // Clear specific strategy data
|
|
879
|
+
* await service.clear("my-strategy");
|
|
880
|
+
*
|
|
881
|
+
* // Clear all strategies' data
|
|
882
|
+
* await service.clear();
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
885
|
+
clear: (strategyName?: StrategyName) => Promise<void>;
|
|
886
|
+
/**
|
|
887
|
+
* Initializes the service by subscribing to backtest signal events.
|
|
888
|
+
* Uses singleshot to ensure initialization happens only once.
|
|
889
|
+
* Automatically called on first use.
|
|
890
|
+
*
|
|
891
|
+
* @example
|
|
892
|
+
* ```typescript
|
|
893
|
+
* const service = new BacktestMarkdownService();
|
|
894
|
+
* await service.init(); // Subscribe to backtest events
|
|
895
|
+
* ```
|
|
896
|
+
*/
|
|
897
|
+
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/**
|
|
901
|
+
* Optimization metric for comparing strategies.
|
|
902
|
+
* Higher values are always better (metric is maximized).
|
|
903
|
+
*/
|
|
904
|
+
type WalkerMetric = "sharpeRatio" | "annualizedSharpeRatio" | "winRate" | "totalPnl" | "certaintyRatio" | "avgPnl" | "expectedYearlyReturns";
|
|
905
|
+
/**
|
|
906
|
+
* Walker schema registered via addWalker().
|
|
907
|
+
* Defines A/B testing configuration for multiple strategies.
|
|
908
|
+
*/
|
|
909
|
+
interface IWalkerSchema {
|
|
910
|
+
/** Unique walker identifier for registration */
|
|
911
|
+
walkerName: WalkerName;
|
|
912
|
+
/** Optional developer note for documentation */
|
|
913
|
+
note?: string;
|
|
914
|
+
/** Exchange to use for backtesting all strategies */
|
|
915
|
+
exchangeName: ExchangeName;
|
|
916
|
+
/** Timeframe generator to use for backtesting all strategies */
|
|
917
|
+
frameName: FrameName;
|
|
918
|
+
/** List of strategy names to compare (must be registered via addStrategy) */
|
|
919
|
+
strategies: StrategyName[];
|
|
920
|
+
/** Metric to optimize (default: "sharpeRatio") */
|
|
921
|
+
metric?: WalkerMetric;
|
|
922
|
+
/** Optional lifecycle event callbacks */
|
|
923
|
+
callbacks?: Partial<IWalkerCallbacks>;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* Optional lifecycle callbacks for walker events.
|
|
927
|
+
* Called during strategy comparison process.
|
|
928
|
+
*/
|
|
929
|
+
interface IWalkerCallbacks {
|
|
930
|
+
/** Called when starting to test a specific strategy */
|
|
931
|
+
onStrategyStart: (strategyName: StrategyName, symbol: string) => void;
|
|
932
|
+
/** Called when a strategy backtest completes */
|
|
933
|
+
onStrategyComplete: (strategyName: StrategyName, symbol: string, stats: BacktestStatistics, metric: number | null) => void;
|
|
934
|
+
/** Called when all strategies have been tested */
|
|
935
|
+
onComplete: (results: IWalkerResults) => void;
|
|
936
|
+
}
|
|
937
|
+
/**
|
|
938
|
+
* Result for a single strategy in the comparison.
|
|
939
|
+
*/
|
|
940
|
+
interface IWalkerStrategyResult {
|
|
941
|
+
/** Strategy name */
|
|
942
|
+
strategyName: StrategyName;
|
|
943
|
+
/** Backtest statistics for this strategy */
|
|
944
|
+
stats: BacktestStatistics;
|
|
945
|
+
/** Metric value used for comparison (null if invalid) */
|
|
946
|
+
metric: number | null;
|
|
947
|
+
/** Rank position (1 = best, 2 = second best, etc.) */
|
|
948
|
+
rank: number;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Complete walker results after comparing all strategies.
|
|
952
|
+
*/
|
|
953
|
+
interface IWalkerResults {
|
|
954
|
+
/** Walker name */
|
|
955
|
+
walkerName: WalkerName;
|
|
956
|
+
/** Symbol tested */
|
|
957
|
+
symbol: string;
|
|
958
|
+
/** Exchange used */
|
|
959
|
+
exchangeName: ExchangeName;
|
|
960
|
+
/** Frame used */
|
|
961
|
+
frameName: FrameName;
|
|
962
|
+
/** Metric used for optimization */
|
|
963
|
+
metric: WalkerMetric;
|
|
964
|
+
/** Total number of strategies tested */
|
|
965
|
+
totalStrategies: number;
|
|
966
|
+
/** Best performing strategy name */
|
|
967
|
+
bestStrategy: StrategyName | null;
|
|
968
|
+
/** Best metric value achieved */
|
|
969
|
+
bestMetric: number | null;
|
|
970
|
+
/** Best strategy statistics */
|
|
971
|
+
bestStats: BacktestStatistics | null;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Unique walker identifier.
|
|
975
|
+
*/
|
|
976
|
+
type WalkerName = string;
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Base parameters common to all sizing calculations.
|
|
980
|
+
*/
|
|
981
|
+
interface ISizingCalculateParamsBase {
|
|
982
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
983
|
+
symbol: string;
|
|
984
|
+
/** Current account balance */
|
|
985
|
+
accountBalance: number;
|
|
986
|
+
/** Planned entry price */
|
|
987
|
+
priceOpen: number;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* Public API parameters for fixed percentage sizing (without method field).
|
|
991
|
+
*/
|
|
992
|
+
interface IPositionSizeFixedPercentageParams extends ISizingCalculateParamsBase {
|
|
993
|
+
/** Stop-loss price */
|
|
994
|
+
priceStopLoss: number;
|
|
995
|
+
}
|
|
996
|
+
/**
|
|
997
|
+
* Public API parameters for Kelly Criterion sizing (without method field).
|
|
998
|
+
*/
|
|
999
|
+
interface IPositionSizeKellyParams extends ISizingCalculateParamsBase {
|
|
1000
|
+
/** Win rate (0-1) */
|
|
1001
|
+
winRate: number;
|
|
1002
|
+
/** Average win/loss ratio */
|
|
1003
|
+
winLossRatio: number;
|
|
1004
|
+
}
|
|
1005
|
+
/**
|
|
1006
|
+
* Public API parameters for ATR-based sizing (without method field).
|
|
1007
|
+
*/
|
|
1008
|
+
interface IPositionSizeATRParams extends ISizingCalculateParamsBase {
|
|
1009
|
+
/** Current ATR value */
|
|
1010
|
+
atr: number;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Parameters for fixed percentage sizing calculation.
|
|
1014
|
+
*/
|
|
1015
|
+
interface ISizingCalculateParamsFixedPercentage extends ISizingCalculateParamsBase {
|
|
1016
|
+
method: "fixed-percentage";
|
|
1017
|
+
/** Stop-loss price */
|
|
1018
|
+
priceStopLoss: number;
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* Parameters for Kelly Criterion sizing calculation.
|
|
1022
|
+
*/
|
|
1023
|
+
interface ISizingCalculateParamsKelly extends ISizingCalculateParamsBase {
|
|
1024
|
+
method: "kelly-criterion";
|
|
1025
|
+
/** Win rate (0-1) */
|
|
1026
|
+
winRate: number;
|
|
1027
|
+
/** Average win/loss ratio */
|
|
1028
|
+
winLossRatio: number;
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Parameters for ATR-based sizing calculation.
|
|
1032
|
+
*/
|
|
1033
|
+
interface ISizingCalculateParamsATR extends ISizingCalculateParamsBase {
|
|
1034
|
+
method: "atr-based";
|
|
1035
|
+
/** Current ATR value */
|
|
1036
|
+
atr: number;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Discriminated union for position size calculation parameters.
|
|
1040
|
+
* Type-safe parameters based on sizing method.
|
|
1041
|
+
*/
|
|
1042
|
+
type ISizingCalculateParams = ISizingCalculateParamsFixedPercentage | ISizingCalculateParamsKelly | ISizingCalculateParamsATR;
|
|
1043
|
+
/**
|
|
1044
|
+
* Fixed percentage sizing parameters for ClientSizing constructor.
|
|
1045
|
+
*/
|
|
1046
|
+
interface ISizingParamsFixedPercentage extends ISizingSchemaFixedPercentage {
|
|
1047
|
+
/** Logger service for debug output */
|
|
1048
|
+
logger: ILogger;
|
|
1049
|
+
}
|
|
1050
|
+
/**
|
|
1051
|
+
* Kelly Criterion sizing parameters for ClientSizing constructor.
|
|
1052
|
+
*/
|
|
1053
|
+
interface ISizingParamsKelly extends ISizingSchemaKelly {
|
|
1054
|
+
/** Logger service for debug output */
|
|
1055
|
+
logger: ILogger;
|
|
1056
|
+
}
|
|
1057
|
+
/**
|
|
1058
|
+
* ATR-based sizing parameters for ClientSizing constructor.
|
|
1059
|
+
*/
|
|
1060
|
+
interface ISizingParamsATR extends ISizingSchemaATR {
|
|
1061
|
+
/** Logger service for debug output */
|
|
1062
|
+
logger: ILogger;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Discriminated union for sizing parameters passed to ClientSizing constructor.
|
|
1066
|
+
* Extends ISizingSchema with logger instance for internal logging.
|
|
1067
|
+
*/
|
|
1068
|
+
type ISizingParams = ISizingParamsFixedPercentage | ISizingParamsKelly | ISizingParamsATR;
|
|
1069
|
+
/**
|
|
1070
|
+
* Callbacks for sizing lifecycle events.
|
|
1071
|
+
*/
|
|
1072
|
+
interface ISizingCallbacks {
|
|
1073
|
+
/**
|
|
1074
|
+
* Called after position size calculation.
|
|
1075
|
+
* Useful for logging or validating the calculated size.
|
|
1076
|
+
*
|
|
1077
|
+
* @param quantity - Calculated position size
|
|
1078
|
+
* @param params - Parameters used for calculation
|
|
1079
|
+
*/
|
|
1080
|
+
onCalculate: (quantity: number, params: ISizingCalculateParams) => void;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Base sizing schema with common fields.
|
|
1084
|
+
*/
|
|
1085
|
+
interface ISizingSchemaBase {
|
|
1086
|
+
/** Unique identifier for this sizing configuration */
|
|
1087
|
+
sizingName: SizingName;
|
|
1088
|
+
/** Optional developer note for documentation */
|
|
1089
|
+
note?: string;
|
|
1090
|
+
/** Maximum position size as % of account (0-100) */
|
|
1091
|
+
maxPositionPercentage?: number;
|
|
1092
|
+
/** Minimum position size (absolute value) */
|
|
1093
|
+
minPositionSize?: number;
|
|
1094
|
+
/** Maximum position size (absolute value) */
|
|
1095
|
+
maxPositionSize?: number;
|
|
1096
|
+
/** Optional lifecycle callbacks */
|
|
1097
|
+
callbacks?: Partial<ISizingCallbacks>;
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Fixed percentage sizing schema.
|
|
1101
|
+
*
|
|
1102
|
+
* @example
|
|
1103
|
+
* ```typescript
|
|
1104
|
+
* addSizing({
|
|
1105
|
+
* sizingName: "conservative",
|
|
1106
|
+
* method: "fixed-percentage",
|
|
1107
|
+
* riskPercentage: 1,
|
|
1108
|
+
* });
|
|
1109
|
+
* ```
|
|
1110
|
+
*/
|
|
1111
|
+
interface ISizingSchemaFixedPercentage extends ISizingSchemaBase {
|
|
1112
|
+
method: "fixed-percentage";
|
|
1113
|
+
/** Risk percentage per trade (0-100) */
|
|
1114
|
+
riskPercentage: number;
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Kelly Criterion sizing schema.
|
|
1118
|
+
*
|
|
1119
|
+
* @example
|
|
1120
|
+
* ```typescript
|
|
1121
|
+
* addSizing({
|
|
1122
|
+
* sizingName: "kelly",
|
|
1123
|
+
* method: "kelly-criterion",
|
|
1124
|
+
* kellyMultiplier: 0.25,
|
|
1125
|
+
* });
|
|
1126
|
+
* ```
|
|
1127
|
+
*/
|
|
1128
|
+
interface ISizingSchemaKelly extends ISizingSchemaBase {
|
|
1129
|
+
method: "kelly-criterion";
|
|
1130
|
+
/** Kelly Criterion multiplier (0-1, default 0.25 for quarter Kelly) */
|
|
1131
|
+
kellyMultiplier?: number;
|
|
1132
|
+
}
|
|
1133
|
+
/**
|
|
1134
|
+
* ATR-based sizing schema.
|
|
1135
|
+
*
|
|
1136
|
+
* @example
|
|
1137
|
+
* ```typescript
|
|
1138
|
+
* addSizing({
|
|
1139
|
+
* sizingName: "atr",
|
|
1140
|
+
* method: "atr-based",
|
|
1141
|
+
* riskPercentage: 2,
|
|
1142
|
+
* atrMultiplier: 2,
|
|
1143
|
+
* });
|
|
1144
|
+
* ```
|
|
1145
|
+
*/
|
|
1146
|
+
interface ISizingSchemaATR extends ISizingSchemaBase {
|
|
1147
|
+
method: "atr-based";
|
|
1148
|
+
/** Risk percentage per trade (0-100) */
|
|
1149
|
+
riskPercentage: number;
|
|
1150
|
+
/** ATR multiplier for stop distance calculation */
|
|
1151
|
+
atrMultiplier?: number;
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Discriminated union for sizing schemas.
|
|
1155
|
+
* Type-safe configuration based on sizing method.
|
|
1156
|
+
*/
|
|
1157
|
+
type ISizingSchema = ISizingSchemaFixedPercentage | ISizingSchemaKelly | ISizingSchemaATR;
|
|
1158
|
+
/**
|
|
1159
|
+
* Sizing interface for position size calculation.
|
|
1160
|
+
* Used internally by strategy execution.
|
|
1161
|
+
*/
|
|
1162
|
+
interface ISizing {
|
|
1163
|
+
/**
|
|
1164
|
+
* Calculates position size based on risk parameters.
|
|
1165
|
+
*
|
|
1166
|
+
* @param params - Calculation parameters (symbol, balance, prices, etc.)
|
|
1167
|
+
* @returns Promise resolving to calculated position size
|
|
1168
|
+
*/
|
|
1169
|
+
calculate: (params: ISizingCalculateParams) => Promise<number>;
|
|
1170
|
+
}
|
|
1171
|
+
/**
|
|
1172
|
+
* Unique identifier for a sizing schema.
|
|
1173
|
+
* Used to retrieve sizing instances via dependency injection.
|
|
1174
|
+
*/
|
|
1175
|
+
type SizingName = string;
|
|
1176
|
+
|
|
1177
|
+
/**
|
|
1178
|
+
* Registers a trading strategy in the framework.
|
|
1179
|
+
*
|
|
1180
|
+
* The strategy will be validated for:
|
|
1181
|
+
* - Signal validation (prices, TP/SL logic, timestamps)
|
|
1182
|
+
* - Interval throttling (prevents signal spam)
|
|
1183
|
+
* - Crash-safe persistence in live mode
|
|
1184
|
+
*
|
|
1185
|
+
* @param strategySchema - Strategy configuration object
|
|
1186
|
+
* @param strategySchema.strategyName - Unique strategy identifier
|
|
1187
|
+
* @param strategySchema.interval - Signal generation interval ("1m" | "3m" | "5m" | "15m" | "30m" | "1h")
|
|
1188
|
+
* @param strategySchema.getSignal - Async function that generates trading signals
|
|
1189
|
+
* @param strategySchema.callbacks - Optional lifecycle callbacks (onOpen, onClose)
|
|
1190
|
+
*
|
|
1191
|
+
* @example
|
|
1192
|
+
* ```typescript
|
|
1193
|
+
* addStrategy({
|
|
1194
|
+
* strategyName: "my-strategy",
|
|
1195
|
+
* interval: "5m",
|
|
1196
|
+
* getSignal: async (symbol) => ({
|
|
1197
|
+
* position: "long",
|
|
1198
|
+
* priceOpen: 50000,
|
|
1199
|
+
* priceTakeProfit: 51000,
|
|
1200
|
+
* priceStopLoss: 49000,
|
|
1201
|
+
* minuteEstimatedTime: 60,
|
|
1202
|
+
* timestamp: Date.now(),
|
|
1203
|
+
* }),
|
|
1204
|
+
* callbacks: {
|
|
1205
|
+
* onOpen: (symbol, signal, currentPrice, backtest) => console.log("Signal opened"),
|
|
1206
|
+
* onClose: (symbol, signal, priceClose, backtest) => console.log("Signal closed"),
|
|
1207
|
+
* },
|
|
1208
|
+
* });
|
|
1209
|
+
* ```
|
|
1210
|
+
*/
|
|
1211
|
+
declare function addStrategy(strategySchema: IStrategySchema): void;
|
|
1212
|
+
/**
|
|
1213
|
+
* Registers an exchange data source in the framework.
|
|
1214
|
+
*
|
|
1215
|
+
* The exchange provides:
|
|
1216
|
+
* - Historical candle data via getCandles
|
|
1217
|
+
* - Price/quantity formatting for the exchange
|
|
1218
|
+
* - VWAP calculation from last 5 1m candles
|
|
1219
|
+
*
|
|
1220
|
+
* @param exchangeSchema - Exchange configuration object
|
|
1221
|
+
* @param exchangeSchema.exchangeName - Unique exchange identifier
|
|
1222
|
+
* @param exchangeSchema.getCandles - Async function to fetch candle data
|
|
1223
|
+
* @param exchangeSchema.formatPrice - Async function to format prices
|
|
1224
|
+
* @param exchangeSchema.formatQuantity - Async function to format quantities
|
|
1225
|
+
* @param exchangeSchema.callbacks - Optional callback for candle data events
|
|
1226
|
+
*
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```typescript
|
|
1229
|
+
* addExchange({
|
|
1230
|
+
* exchangeName: "binance",
|
|
1231
|
+
* getCandles: async (symbol, interval, since, limit) => {
|
|
1232
|
+
* // Fetch from Binance API or database
|
|
1233
|
+
* return [{
|
|
1234
|
+
* timestamp: Date.now(),
|
|
1235
|
+
* open: 50000,
|
|
1236
|
+
* high: 51000,
|
|
1237
|
+
* low: 49000,
|
|
1238
|
+
* close: 50500,
|
|
1239
|
+
* volume: 1000,
|
|
1240
|
+
* }];
|
|
1241
|
+
* },
|
|
1242
|
+
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
1243
|
+
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
1244
|
+
* });
|
|
1245
|
+
* ```
|
|
1246
|
+
*/
|
|
1247
|
+
declare function addExchange(exchangeSchema: IExchangeSchema): void;
|
|
1248
|
+
/**
|
|
1249
|
+
* Registers a timeframe generator for backtesting.
|
|
1250
|
+
*
|
|
1251
|
+
* The frame defines:
|
|
1252
|
+
* - Start and end dates for backtest period
|
|
1253
|
+
* - Interval for timeframe generation
|
|
1254
|
+
* - Callback for timeframe generation events
|
|
1255
|
+
*
|
|
1256
|
+
* @param frameSchema - Frame configuration object
|
|
1257
|
+
* @param frameSchema.frameName - Unique frame identifier
|
|
1258
|
+
* @param frameSchema.interval - Timeframe interval ("1m" | "3m" | "5m" | "15m" | "30m" | "1h" | "2h" | "4h" | "6h" | "8h" | "12h" | "1d" | "3d")
|
|
1259
|
+
* @param frameSchema.startDate - Start date for timeframe generation
|
|
1260
|
+
* @param frameSchema.endDate - End date for timeframe generation
|
|
1261
|
+
* @param frameSchema.callbacks - Optional callback for timeframe events
|
|
1262
|
+
*
|
|
1263
|
+
* @example
|
|
1264
|
+
* ```typescript
|
|
1265
|
+
* addFrame({
|
|
1266
|
+
* frameName: "1d-backtest",
|
|
1267
|
+
* interval: "1m",
|
|
1268
|
+
* startDate: new Date("2024-01-01T00:00:00Z"),
|
|
1269
|
+
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
1270
|
+
* callbacks: {
|
|
1271
|
+
* onTimeframe: (timeframe, startDate, endDate, interval) => {
|
|
1272
|
+
* console.log(`Generated ${timeframe.length} timeframes`);
|
|
1273
|
+
* },
|
|
1274
|
+
* },
|
|
1275
|
+
* });
|
|
1276
|
+
* ```
|
|
1277
|
+
*/
|
|
1278
|
+
declare function addFrame(frameSchema: IFrameSchema): void;
|
|
1279
|
+
/**
|
|
1280
|
+
* Registers a walker for strategy comparison.
|
|
1281
|
+
*
|
|
1282
|
+
* The walker executes backtests for multiple strategies on the same
|
|
1283
|
+
* historical data and compares their performance using a specified metric.
|
|
1284
|
+
*
|
|
1285
|
+
* @param walkerSchema - Walker configuration object
|
|
1286
|
+
* @param walkerSchema.walkerName - Unique walker identifier
|
|
1287
|
+
* @param walkerSchema.exchangeName - Exchange to use for all strategies
|
|
1288
|
+
* @param walkerSchema.frameName - Timeframe to use for all strategies
|
|
1289
|
+
* @param walkerSchema.strategies - Array of strategy names to compare
|
|
1290
|
+
* @param walkerSchema.metric - Metric to optimize (default: "sharpeRatio")
|
|
1291
|
+
* @param walkerSchema.callbacks - Optional lifecycle callbacks
|
|
1292
|
+
*
|
|
1293
|
+
* @example
|
|
1294
|
+
* ```typescript
|
|
1295
|
+
* addWalker({
|
|
1296
|
+
* walkerName: "llm-prompt-optimizer",
|
|
1297
|
+
* exchangeName: "binance",
|
|
1298
|
+
* frameName: "1d-backtest",
|
|
1299
|
+
* strategies: [
|
|
1300
|
+
* "my-strategy-v1",
|
|
1301
|
+
* "my-strategy-v2",
|
|
1302
|
+
* "my-strategy-v3"
|
|
1303
|
+
* ],
|
|
1304
|
+
* metric: "sharpeRatio",
|
|
1305
|
+
* callbacks: {
|
|
1306
|
+
* onStrategyComplete: (strategyName, symbol, stats, metric) => {
|
|
1307
|
+
* console.log(`${strategyName}: ${metric}`);
|
|
1308
|
+
* },
|
|
1309
|
+
* onComplete: (results) => {
|
|
1310
|
+
* console.log(`Best strategy: ${results.bestStrategy}`);
|
|
1311
|
+
* }
|
|
1312
|
+
* }
|
|
1313
|
+
* });
|
|
1314
|
+
* ```
|
|
1315
|
+
*/
|
|
1316
|
+
declare function addWalker(walkerSchema: IWalkerSchema): void;
|
|
1317
|
+
/**
|
|
1318
|
+
* Registers a position sizing configuration in the framework.
|
|
1319
|
+
*
|
|
1320
|
+
* The sizing configuration defines:
|
|
1321
|
+
* - Position sizing method (fixed-percentage, kelly-criterion, atr-based)
|
|
1322
|
+
* - Risk parameters (risk percentage, Kelly multiplier, ATR multiplier)
|
|
1323
|
+
* - Position constraints (min/max size, max position percentage)
|
|
1324
|
+
* - Callback for calculation events
|
|
1325
|
+
*
|
|
1326
|
+
* @param sizingSchema - Sizing configuration object (discriminated union)
|
|
1327
|
+
* @param sizingSchema.sizingName - Unique sizing identifier
|
|
1328
|
+
* @param sizingSchema.method - Sizing method ("fixed-percentage" | "kelly-criterion" | "atr-based")
|
|
1329
|
+
* @param sizingSchema.riskPercentage - Risk percentage per trade (for fixed-percentage and atr-based)
|
|
1330
|
+
* @param sizingSchema.kellyMultiplier - Kelly multiplier (for kelly-criterion, default: 0.25)
|
|
1331
|
+
* @param sizingSchema.atrMultiplier - ATR multiplier (for atr-based, default: 2)
|
|
1332
|
+
* @param sizingSchema.maxPositionPercentage - Optional max position size as % of account
|
|
1333
|
+
* @param sizingSchema.minPositionSize - Optional minimum position size
|
|
1334
|
+
* @param sizingSchema.maxPositionSize - Optional maximum position size
|
|
1335
|
+
* @param sizingSchema.callbacks - Optional lifecycle callbacks
|
|
1336
|
+
*
|
|
1337
|
+
* @example
|
|
1338
|
+
* ```typescript
|
|
1339
|
+
* // Fixed percentage sizing
|
|
1340
|
+
* addSizing({
|
|
1341
|
+
* sizingName: "conservative",
|
|
1342
|
+
* method: "fixed-percentage",
|
|
1343
|
+
* riskPercentage: 1,
|
|
1344
|
+
* maxPositionPercentage: 10,
|
|
1345
|
+
* });
|
|
1346
|
+
*
|
|
1347
|
+
* // Kelly Criterion sizing
|
|
1348
|
+
* addSizing({
|
|
1349
|
+
* sizingName: "kelly",
|
|
1350
|
+
* method: "kelly-criterion",
|
|
1351
|
+
* kellyMultiplier: 0.25,
|
|
1352
|
+
* maxPositionPercentage: 20,
|
|
1353
|
+
* });
|
|
1354
|
+
*
|
|
1355
|
+
* // ATR-based sizing
|
|
1356
|
+
* addSizing({
|
|
1357
|
+
* sizingName: "atr-dynamic",
|
|
1358
|
+
* method: "atr-based",
|
|
1359
|
+
* riskPercentage: 2,
|
|
1360
|
+
* atrMultiplier: 2,
|
|
1361
|
+
* callbacks: {
|
|
1362
|
+
* onCalculate: (quantity, params) => {
|
|
1363
|
+
* console.log(`Calculated size: ${quantity} for ${params.symbol}`);
|
|
1364
|
+
* },
|
|
1365
|
+
* },
|
|
1366
|
+
* });
|
|
1367
|
+
* ```
|
|
1368
|
+
*/
|
|
1369
|
+
declare function addSizing(sizingSchema: ISizingSchema): void;
|
|
1370
|
+
/**
|
|
1371
|
+
* Registers a risk management configuration in the framework.
|
|
1372
|
+
*
|
|
1373
|
+
* The risk configuration defines:
|
|
1374
|
+
* - Maximum concurrent positions across all strategies
|
|
1375
|
+
* - Custom validations for advanced risk logic (portfolio metrics, correlations, etc.)
|
|
1376
|
+
* - Callbacks for rejected/allowed signals
|
|
1377
|
+
*
|
|
1378
|
+
* Multiple ClientStrategy instances share the same ClientRisk instance,
|
|
1379
|
+
* enabling cross-strategy risk analysis. ClientRisk tracks all active positions
|
|
1380
|
+
* and provides access to them via validation functions.
|
|
1381
|
+
*
|
|
1382
|
+
* @param riskSchema - Risk configuration object
|
|
1383
|
+
* @param riskSchema.riskName - Unique risk profile identifier
|
|
1384
|
+
* @param riskSchema.maxConcurrentPositions - Optional max number of open positions across all strategies
|
|
1385
|
+
* @param riskSchema.validations - Optional custom validation functions with access to params and active positions
|
|
1386
|
+
* @param riskSchema.callbacks - Optional lifecycle callbacks (onRejected, onAllowed)
|
|
1387
|
+
*
|
|
1388
|
+
* @example
|
|
1389
|
+
* ```typescript
|
|
1390
|
+
* // Basic risk limit
|
|
1391
|
+
* addRisk({
|
|
1392
|
+
* riskName: "conservative",
|
|
1393
|
+
* maxConcurrentPositions: 5,
|
|
1394
|
+
* });
|
|
1395
|
+
*
|
|
1396
|
+
* // With custom validations (access to signal data and portfolio state)
|
|
1397
|
+
* addRisk({
|
|
1398
|
+
* riskName: "advanced",
|
|
1399
|
+
* maxConcurrentPositions: 10,
|
|
1400
|
+
* validations: [
|
|
1401
|
+
* {
|
|
1402
|
+
* validate: async ({ params }) => {
|
|
1403
|
+
* // params contains: symbol, strategyName, exchangeName, signal, currentPrice, timestamp
|
|
1404
|
+
* // Calculate portfolio metrics from external data source
|
|
1405
|
+
* const portfolio = await getPortfolioState();
|
|
1406
|
+
* if (portfolio.drawdown > 20) {
|
|
1407
|
+
* throw new Error("Portfolio drawdown exceeds 20%");
|
|
1408
|
+
* }
|
|
1409
|
+
* },
|
|
1410
|
+
* docDescription: "Prevents trading during high drawdown",
|
|
1411
|
+
* },
|
|
1412
|
+
* ({ params }) => {
|
|
1413
|
+
* // Access signal details
|
|
1414
|
+
* const positionValue = calculatePositionValue(params.signal, params.currentPrice);
|
|
1415
|
+
* if (positionValue > 10000) {
|
|
1416
|
+
* throw new Error("Position value exceeds $10,000 limit");
|
|
1417
|
+
* }
|
|
1418
|
+
* },
|
|
1419
|
+
* ],
|
|
1420
|
+
* callbacks: {
|
|
1421
|
+
* onRejected: (symbol, reason, limit, params) => {
|
|
1422
|
+
* console.log(`[RISK] Signal rejected for ${symbol}: ${reason}`);
|
|
1423
|
+
* },
|
|
1424
|
+
* onAllowed: (symbol, params) => {
|
|
1425
|
+
* console.log(`[RISK] Signal allowed for ${symbol}`);
|
|
1426
|
+
* },
|
|
1427
|
+
* },
|
|
1428
|
+
* });
|
|
1429
|
+
* ```
|
|
1430
|
+
*/
|
|
1431
|
+
declare function addRisk(riskSchema: IRiskSchema): void;
|
|
1432
|
+
|
|
1433
|
+
/**
|
|
1434
|
+
* Returns a list of all registered exchange schemas.
|
|
1435
|
+
*
|
|
1436
|
+
* Retrieves all exchanges that have been registered via addExchange().
|
|
1437
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
1438
|
+
*
|
|
1439
|
+
* @returns Array of exchange schemas with their configurations
|
|
1440
|
+
*
|
|
1441
|
+
* @example
|
|
1442
|
+
* ```typescript
|
|
1443
|
+
* import { listExchanges, addExchange } from "backtest-kit";
|
|
1444
|
+
*
|
|
1445
|
+
* addExchange({
|
|
1446
|
+
* exchangeName: "binance",
|
|
1447
|
+
* note: "Binance cryptocurrency exchange",
|
|
1448
|
+
* getCandles: async (symbol, interval, since, limit) => [...],
|
|
1449
|
+
* formatPrice: async (symbol, price) => price.toFixed(2),
|
|
1450
|
+
* formatQuantity: async (symbol, quantity) => quantity.toFixed(8),
|
|
1451
|
+
* });
|
|
1452
|
+
*
|
|
1453
|
+
* const exchanges = listExchanges();
|
|
1454
|
+
* console.log(exchanges);
|
|
1455
|
+
* // [{ exchangeName: "binance", note: "Binance cryptocurrency exchange", ... }]
|
|
1456
|
+
* ```
|
|
1457
|
+
*/
|
|
1458
|
+
declare function listExchanges(): Promise<IExchangeSchema[]>;
|
|
1459
|
+
/**
|
|
1460
|
+
* Returns a list of all registered strategy schemas.
|
|
1461
|
+
*
|
|
1462
|
+
* Retrieves all strategies that have been registered via addStrategy().
|
|
1463
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
1464
|
+
*
|
|
1465
|
+
* @returns Array of strategy schemas with their configurations
|
|
1466
|
+
*
|
|
1467
|
+
* @example
|
|
1468
|
+
* ```typescript
|
|
1469
|
+
* import { listStrategies, addStrategy } from "backtest-kit";
|
|
1470
|
+
*
|
|
1471
|
+
* addStrategy({
|
|
1472
|
+
* strategyName: "my-strategy",
|
|
1473
|
+
* note: "Simple moving average crossover strategy",
|
|
1474
|
+
* interval: "5m",
|
|
1475
|
+
* getSignal: async (symbol) => ({
|
|
1476
|
+
* position: "long",
|
|
1477
|
+
* priceOpen: 50000,
|
|
1478
|
+
* priceTakeProfit: 51000,
|
|
1479
|
+
* priceStopLoss: 49000,
|
|
1480
|
+
* minuteEstimatedTime: 60,
|
|
1481
|
+
* }),
|
|
1482
|
+
* });
|
|
1483
|
+
*
|
|
1484
|
+
* const strategies = listStrategies();
|
|
1485
|
+
* console.log(strategies);
|
|
1486
|
+
* // [{ strategyName: "my-strategy", note: "Simple moving average...", ... }]
|
|
731
1487
|
* ```
|
|
732
1488
|
*/
|
|
733
1489
|
declare function listStrategies(): Promise<IStrategySchema[]>;
|
|
@@ -757,6 +1513,102 @@ declare function listStrategies(): Promise<IStrategySchema[]>;
|
|
|
757
1513
|
* ```
|
|
758
1514
|
*/
|
|
759
1515
|
declare function listFrames(): Promise<IFrameSchema[]>;
|
|
1516
|
+
/**
|
|
1517
|
+
* Returns a list of all registered walker schemas.
|
|
1518
|
+
*
|
|
1519
|
+
* Retrieves all walkers that have been registered via addWalker().
|
|
1520
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
1521
|
+
*
|
|
1522
|
+
* @returns Array of walker schemas with their configurations
|
|
1523
|
+
*
|
|
1524
|
+
* @example
|
|
1525
|
+
* ```typescript
|
|
1526
|
+
* import { listWalkers, addWalker } from "backtest-kit";
|
|
1527
|
+
*
|
|
1528
|
+
* addWalker({
|
|
1529
|
+
* walkerName: "llm-prompt-optimizer",
|
|
1530
|
+
* note: "Compare LLM-based trading strategies",
|
|
1531
|
+
* exchangeName: "binance",
|
|
1532
|
+
* frameName: "1d-backtest",
|
|
1533
|
+
* strategies: ["my-strategy-v1", "my-strategy-v2"],
|
|
1534
|
+
* metric: "sharpeRatio",
|
|
1535
|
+
* });
|
|
1536
|
+
*
|
|
1537
|
+
* const walkers = listWalkers();
|
|
1538
|
+
* console.log(walkers);
|
|
1539
|
+
* // [{ walkerName: "llm-prompt-optimizer", note: "Compare LLM...", ... }]
|
|
1540
|
+
* ```
|
|
1541
|
+
*/
|
|
1542
|
+
declare function listWalkers(): Promise<IWalkerSchema[]>;
|
|
1543
|
+
/**
|
|
1544
|
+
* Returns a list of all registered sizing schemas.
|
|
1545
|
+
*
|
|
1546
|
+
* Retrieves all sizing configurations that have been registered via addSizing().
|
|
1547
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
1548
|
+
*
|
|
1549
|
+
* @returns Array of sizing schemas with their configurations
|
|
1550
|
+
*
|
|
1551
|
+
* @example
|
|
1552
|
+
* ```typescript
|
|
1553
|
+
* import { listSizings, addSizing } from "backtest-kit";
|
|
1554
|
+
*
|
|
1555
|
+
* addSizing({
|
|
1556
|
+
* sizingName: "conservative",
|
|
1557
|
+
* note: "Low risk fixed percentage sizing",
|
|
1558
|
+
* method: "fixed-percentage",
|
|
1559
|
+
* riskPercentage: 1,
|
|
1560
|
+
* maxPositionPercentage: 10,
|
|
1561
|
+
* });
|
|
1562
|
+
*
|
|
1563
|
+
* addSizing({
|
|
1564
|
+
* sizingName: "kelly",
|
|
1565
|
+
* note: "Kelly Criterion with quarter multiplier",
|
|
1566
|
+
* method: "kelly-criterion",
|
|
1567
|
+
* kellyMultiplier: 0.25,
|
|
1568
|
+
* });
|
|
1569
|
+
*
|
|
1570
|
+
* const sizings = listSizings();
|
|
1571
|
+
* console.log(sizings);
|
|
1572
|
+
* // [
|
|
1573
|
+
* // { sizingName: "conservative", method: "fixed-percentage", ... },
|
|
1574
|
+
* // { sizingName: "kelly", method: "kelly-criterion", ... }
|
|
1575
|
+
* // ]
|
|
1576
|
+
* ```
|
|
1577
|
+
*/
|
|
1578
|
+
declare function listSizings(): Promise<ISizingSchema[]>;
|
|
1579
|
+
/**
|
|
1580
|
+
* Returns a list of all registered risk schemas.
|
|
1581
|
+
*
|
|
1582
|
+
* Retrieves all risk configurations that have been registered via addRisk().
|
|
1583
|
+
* Useful for debugging, documentation, or building dynamic UIs.
|
|
1584
|
+
*
|
|
1585
|
+
* @returns Array of risk schemas with their configurations
|
|
1586
|
+
*
|
|
1587
|
+
* @example
|
|
1588
|
+
* ```typescript
|
|
1589
|
+
* import { listRisks, addRisk } from "backtest-kit";
|
|
1590
|
+
*
|
|
1591
|
+
* addRisk({
|
|
1592
|
+
* riskName: "conservative",
|
|
1593
|
+
* note: "Conservative risk management with tight position limits",
|
|
1594
|
+
* maxConcurrentPositions: 5,
|
|
1595
|
+
* });
|
|
1596
|
+
*
|
|
1597
|
+
* addRisk({
|
|
1598
|
+
* riskName: "aggressive",
|
|
1599
|
+
* note: "Aggressive risk management with loose limits",
|
|
1600
|
+
* maxConcurrentPositions: 10,
|
|
1601
|
+
* });
|
|
1602
|
+
*
|
|
1603
|
+
* const risks = listRisks();
|
|
1604
|
+
* console.log(risks);
|
|
1605
|
+
* // [
|
|
1606
|
+
* // { riskName: "conservative", maxConcurrentPositions: 5, ... },
|
|
1607
|
+
* // { riskName: "aggressive", maxConcurrentPositions: 10, ... }
|
|
1608
|
+
* // ]
|
|
1609
|
+
* ```
|
|
1610
|
+
*/
|
|
1611
|
+
declare function listRisks(): Promise<IRiskSchema[]>;
|
|
760
1612
|
|
|
761
1613
|
/**
|
|
762
1614
|
* Contract for background execution completion events.
|
|
@@ -850,6 +1702,8 @@ type PerformanceMetricType = "backtest_total" | "backtest_timeframe" | "backtest
|
|
|
850
1702
|
interface PerformanceContract {
|
|
851
1703
|
/** Timestamp when the metric was recorded (milliseconds since epoch) */
|
|
852
1704
|
timestamp: number;
|
|
1705
|
+
/** Timestamp of the previous event (milliseconds since epoch, null for first event) */
|
|
1706
|
+
previousTimestamp: number | null;
|
|
853
1707
|
/** Type of operation being measured */
|
|
854
1708
|
metricType: PerformanceMetricType;
|
|
855
1709
|
/** Duration of the operation in milliseconds */
|
|
@@ -864,6 +1718,37 @@ interface PerformanceContract {
|
|
|
864
1718
|
backtest: boolean;
|
|
865
1719
|
}
|
|
866
1720
|
|
|
1721
|
+
/**
|
|
1722
|
+
* Contract for walker progress events during strategy comparison.
|
|
1723
|
+
* Emitted each time a strategy completes testing with its current ranking.
|
|
1724
|
+
*/
|
|
1725
|
+
interface WalkerContract {
|
|
1726
|
+
/** Walker name */
|
|
1727
|
+
walkerName: WalkerName;
|
|
1728
|
+
/** Exchange name */
|
|
1729
|
+
exchangeName: ExchangeName;
|
|
1730
|
+
/** Frame name */
|
|
1731
|
+
frameName: string;
|
|
1732
|
+
/** Symbol being tested */
|
|
1733
|
+
symbol: string;
|
|
1734
|
+
/** Strategy that just completed */
|
|
1735
|
+
strategyName: StrategyName;
|
|
1736
|
+
/** Backtest statistics for this strategy */
|
|
1737
|
+
stats: BacktestStatistics;
|
|
1738
|
+
/** Metric value for this strategy (null if invalid) */
|
|
1739
|
+
metricValue: number | null;
|
|
1740
|
+
/** Metric being optimized */
|
|
1741
|
+
metric: WalkerMetric;
|
|
1742
|
+
/** Current best metric value across all tested strategies so far */
|
|
1743
|
+
bestMetric: number | null;
|
|
1744
|
+
/** Current best strategy name */
|
|
1745
|
+
bestStrategy: StrategyName | null;
|
|
1746
|
+
/** Number of strategies tested so far */
|
|
1747
|
+
strategiesTested: number;
|
|
1748
|
+
/** Total number of strategies to test */
|
|
1749
|
+
totalStrategies: number;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
867
1752
|
/**
|
|
868
1753
|
* Subscribes to all signal events with queued async processing.
|
|
869
1754
|
*
|
|
@@ -1034,9 +1919,9 @@ declare function listenSignalBacktestOnce(filterFn: (event: IStrategyTickResult)
|
|
|
1034
1919
|
*/
|
|
1035
1920
|
declare function listenError(fn: (error: Error) => void): () => void;
|
|
1036
1921
|
/**
|
|
1037
|
-
* Subscribes to background execution completion events with queued async processing.
|
|
1922
|
+
* Subscribes to live background execution completion events with queued async processing.
|
|
1038
1923
|
*
|
|
1039
|
-
* Emits when Live.background()
|
|
1924
|
+
* Emits when Live.background() completes execution.
|
|
1040
1925
|
* Events are processed sequentially in order received, even if callback is async.
|
|
1041
1926
|
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
1042
1927
|
*
|
|
@@ -1045,29 +1930,82 @@ declare function listenError(fn: (error: Error) => void): () => void;
|
|
|
1045
1930
|
*
|
|
1046
1931
|
* @example
|
|
1047
1932
|
* ```typescript
|
|
1048
|
-
* import {
|
|
1933
|
+
* import { listenDoneLive, Live } from "backtest-kit";
|
|
1049
1934
|
*
|
|
1050
|
-
* const unsubscribe =
|
|
1051
|
-
* console.log("
|
|
1052
|
-
*
|
|
1053
|
-
*
|
|
1054
|
-
*
|
|
1935
|
+
* const unsubscribe = listenDoneLive((event) => {
|
|
1936
|
+
* console.log("Live completed:", event.strategyName, event.exchangeName, event.symbol);
|
|
1937
|
+
* });
|
|
1938
|
+
*
|
|
1939
|
+
* Live.background("BTCUSDT", {
|
|
1940
|
+
* strategyName: "my-strategy",
|
|
1941
|
+
* exchangeName: "binance"
|
|
1055
1942
|
* });
|
|
1056
1943
|
*
|
|
1944
|
+
* // Later: stop listening
|
|
1945
|
+
* unsubscribe();
|
|
1946
|
+
* ```
|
|
1947
|
+
*/
|
|
1948
|
+
declare function listenDoneLive(fn: (event: DoneContract) => void): () => void;
|
|
1949
|
+
/**
|
|
1950
|
+
* Subscribes to filtered live background execution completion events with one-time execution.
|
|
1951
|
+
*
|
|
1952
|
+
* Emits when Live.background() completes execution.
|
|
1953
|
+
* Executes callback once and automatically unsubscribes.
|
|
1954
|
+
*
|
|
1955
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
1956
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
1957
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
1958
|
+
*
|
|
1959
|
+
* @example
|
|
1960
|
+
* ```typescript
|
|
1961
|
+
* import { listenDoneLiveOnce, Live } from "backtest-kit";
|
|
1962
|
+
*
|
|
1963
|
+
* // Wait for first live completion
|
|
1964
|
+
* listenDoneLiveOnce(
|
|
1965
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
1966
|
+
* (event) => console.log("BTCUSDT live completed:", event.strategyName)
|
|
1967
|
+
* );
|
|
1968
|
+
*
|
|
1057
1969
|
* Live.background("BTCUSDT", {
|
|
1058
1970
|
* strategyName: "my-strategy",
|
|
1059
1971
|
* exchangeName: "binance"
|
|
1060
1972
|
* });
|
|
1973
|
+
* ```
|
|
1974
|
+
*/
|
|
1975
|
+
declare function listenDoneLiveOnce(filterFn: (event: DoneContract) => boolean, fn: (event: DoneContract) => void): () => void;
|
|
1976
|
+
/**
|
|
1977
|
+
* Subscribes to backtest background execution completion events with queued async processing.
|
|
1978
|
+
*
|
|
1979
|
+
* Emits when Backtest.background() completes execution.
|
|
1980
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
1981
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
1982
|
+
*
|
|
1983
|
+
* @param fn - Callback function to handle completion events
|
|
1984
|
+
* @returns Unsubscribe function to stop listening to events
|
|
1985
|
+
*
|
|
1986
|
+
* @example
|
|
1987
|
+
* ```typescript
|
|
1988
|
+
* import { listenDoneBacktest, Backtest } from "backtest-kit";
|
|
1989
|
+
*
|
|
1990
|
+
* const unsubscribe = listenDoneBacktest((event) => {
|
|
1991
|
+
* console.log("Backtest completed:", event.strategyName, event.exchangeName, event.symbol);
|
|
1992
|
+
* });
|
|
1993
|
+
*
|
|
1994
|
+
* Backtest.background("BTCUSDT", {
|
|
1995
|
+
* strategyName: "my-strategy",
|
|
1996
|
+
* exchangeName: "binance",
|
|
1997
|
+
* frameName: "1d-backtest"
|
|
1998
|
+
* });
|
|
1061
1999
|
*
|
|
1062
2000
|
* // Later: stop listening
|
|
1063
2001
|
* unsubscribe();
|
|
1064
2002
|
* ```
|
|
1065
2003
|
*/
|
|
1066
|
-
declare function
|
|
2004
|
+
declare function listenDoneBacktest(fn: (event: DoneContract) => void): () => void;
|
|
1067
2005
|
/**
|
|
1068
|
-
* Subscribes to filtered background execution completion events with one-time execution.
|
|
2006
|
+
* Subscribes to filtered backtest background execution completion events with one-time execution.
|
|
1069
2007
|
*
|
|
1070
|
-
* Emits when
|
|
2008
|
+
* Emits when Backtest.background() completes execution.
|
|
1071
2009
|
* Executes callback once and automatically unsubscribes.
|
|
1072
2010
|
*
|
|
1073
2011
|
* @param filterFn - Predicate to filter which events trigger the callback
|
|
@@ -1076,11 +2014,11 @@ declare function listenDone(fn: (event: DoneContract) => void): () => void;
|
|
|
1076
2014
|
*
|
|
1077
2015
|
* @example
|
|
1078
2016
|
* ```typescript
|
|
1079
|
-
* import {
|
|
2017
|
+
* import { listenDoneBacktestOnce, Backtest } from "backtest-kit";
|
|
1080
2018
|
*
|
|
1081
2019
|
* // Wait for first backtest completion
|
|
1082
|
-
*
|
|
1083
|
-
* (event) => event.
|
|
2020
|
+
* listenDoneBacktestOnce(
|
|
2021
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
1084
2022
|
* (event) => console.log("BTCUSDT backtest completed:", event.strategyName)
|
|
1085
2023
|
* );
|
|
1086
2024
|
*
|
|
@@ -1091,7 +2029,60 @@ declare function listenDone(fn: (event: DoneContract) => void): () => void;
|
|
|
1091
2029
|
* });
|
|
1092
2030
|
* ```
|
|
1093
2031
|
*/
|
|
1094
|
-
declare function
|
|
2032
|
+
declare function listenDoneBacktestOnce(filterFn: (event: DoneContract) => boolean, fn: (event: DoneContract) => void): () => void;
|
|
2033
|
+
/**
|
|
2034
|
+
* Subscribes to walker background execution completion events with queued async processing.
|
|
2035
|
+
*
|
|
2036
|
+
* Emits when Walker.background() completes execution.
|
|
2037
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2038
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2039
|
+
*
|
|
2040
|
+
* @param fn - Callback function to handle completion events
|
|
2041
|
+
* @returns Unsubscribe function to stop listening to events
|
|
2042
|
+
*
|
|
2043
|
+
* @example
|
|
2044
|
+
* ```typescript
|
|
2045
|
+
* import { listenDoneWalker, Walker } from "backtest-kit";
|
|
2046
|
+
*
|
|
2047
|
+
* const unsubscribe = listenDoneWalker((event) => {
|
|
2048
|
+
* console.log("Walker completed:", event.strategyName, event.exchangeName, event.symbol);
|
|
2049
|
+
* });
|
|
2050
|
+
*
|
|
2051
|
+
* Walker.background("BTCUSDT", {
|
|
2052
|
+
* walkerName: "my-walker"
|
|
2053
|
+
* });
|
|
2054
|
+
*
|
|
2055
|
+
* // Later: stop listening
|
|
2056
|
+
* unsubscribe();
|
|
2057
|
+
* ```
|
|
2058
|
+
*/
|
|
2059
|
+
declare function listenDoneWalker(fn: (event: DoneContract) => void): () => void;
|
|
2060
|
+
/**
|
|
2061
|
+
* Subscribes to filtered walker background execution completion events with one-time execution.
|
|
2062
|
+
*
|
|
2063
|
+
* Emits when Walker.background() completes execution.
|
|
2064
|
+
* Executes callback once and automatically unsubscribes.
|
|
2065
|
+
*
|
|
2066
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
2067
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
2068
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
2069
|
+
*
|
|
2070
|
+
* @example
|
|
2071
|
+
* ```typescript
|
|
2072
|
+
* import { listenDoneWalkerOnce, Walker } from "backtest-kit";
|
|
2073
|
+
*
|
|
2074
|
+
* // Wait for first walker completion
|
|
2075
|
+
* listenDoneWalkerOnce(
|
|
2076
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
2077
|
+
* (event) => console.log("BTCUSDT walker completed:", event.strategyName)
|
|
2078
|
+
* );
|
|
2079
|
+
*
|
|
2080
|
+
* Walker.background("BTCUSDT", {
|
|
2081
|
+
* walkerName: "my-walker"
|
|
2082
|
+
* });
|
|
2083
|
+
* ```
|
|
2084
|
+
*/
|
|
2085
|
+
declare function listenDoneWalkerOnce(filterFn: (event: DoneContract) => boolean, fn: (event: DoneContract) => void): () => void;
|
|
1095
2086
|
/**
|
|
1096
2087
|
* Subscribes to backtest progress events with queued async processing.
|
|
1097
2088
|
*
|
|
@@ -1155,7 +2146,135 @@ declare function listenProgress(fn: (event: ProgressContract) => void): () => vo
|
|
|
1155
2146
|
* unsubscribe();
|
|
1156
2147
|
* ```
|
|
1157
2148
|
*/
|
|
1158
|
-
declare function listenPerformance(fn: (event: PerformanceContract) => void): () => void;
|
|
2149
|
+
declare function listenPerformance(fn: (event: PerformanceContract) => void): () => void;
|
|
2150
|
+
/**
|
|
2151
|
+
* Subscribes to walker progress events with queued async processing.
|
|
2152
|
+
*
|
|
2153
|
+
* Emits during Walker.run() execution after each strategy completes.
|
|
2154
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2155
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2156
|
+
*
|
|
2157
|
+
* @param fn - Callback function to handle walker progress events
|
|
2158
|
+
* @returns Unsubscribe function to stop listening to events
|
|
2159
|
+
*
|
|
2160
|
+
* @example
|
|
2161
|
+
* ```typescript
|
|
2162
|
+
* import { listenWalker, Walker } from "backtest-kit";
|
|
2163
|
+
*
|
|
2164
|
+
* const unsubscribe = listenWalker((event) => {
|
|
2165
|
+
* console.log(`Progress: ${event.strategiesTested} / ${event.totalStrategies}`);
|
|
2166
|
+
* console.log(`Best strategy: ${event.bestStrategy} (${event.bestMetric})`);
|
|
2167
|
+
* console.log(`Current strategy: ${event.strategyName} (${event.metricValue})`);
|
|
2168
|
+
* });
|
|
2169
|
+
*
|
|
2170
|
+
* Walker.run("BTCUSDT", {
|
|
2171
|
+
* walkerName: "my-walker",
|
|
2172
|
+
* exchangeName: "binance",
|
|
2173
|
+
* frameName: "1d-backtest"
|
|
2174
|
+
* });
|
|
2175
|
+
*
|
|
2176
|
+
* // Later: stop listening
|
|
2177
|
+
* unsubscribe();
|
|
2178
|
+
* ```
|
|
2179
|
+
*/
|
|
2180
|
+
declare function listenWalker(fn: (event: WalkerContract) => void): () => void;
|
|
2181
|
+
/**
|
|
2182
|
+
* Subscribes to filtered walker progress events with one-time execution.
|
|
2183
|
+
*
|
|
2184
|
+
* Listens for events matching the filter predicate, then executes callback once
|
|
2185
|
+
* and automatically unsubscribes. Useful for waiting for specific walker conditions.
|
|
2186
|
+
*
|
|
2187
|
+
* @param filterFn - Predicate to filter which events trigger the callback
|
|
2188
|
+
* @param fn - Callback function to handle the filtered event (called only once)
|
|
2189
|
+
* @returns Unsubscribe function to cancel the listener before it fires
|
|
2190
|
+
*
|
|
2191
|
+
* @example
|
|
2192
|
+
* ```typescript
|
|
2193
|
+
* import { listenWalkerOnce, Walker } from "backtest-kit";
|
|
2194
|
+
*
|
|
2195
|
+
* // Wait for walker to complete all strategies
|
|
2196
|
+
* listenWalkerOnce(
|
|
2197
|
+
* (event) => event.strategiesTested === event.totalStrategies,
|
|
2198
|
+
* (event) => {
|
|
2199
|
+
* console.log("Walker completed!");
|
|
2200
|
+
* console.log("Best strategy:", event.bestStrategy, event.bestMetric);
|
|
2201
|
+
* }
|
|
2202
|
+
* );
|
|
2203
|
+
*
|
|
2204
|
+
* // Wait for specific strategy to be tested
|
|
2205
|
+
* const cancel = listenWalkerOnce(
|
|
2206
|
+
* (event) => event.strategyName === "my-strategy-v2",
|
|
2207
|
+
* (event) => console.log("Strategy v2 tested:", event.metricValue)
|
|
2208
|
+
* );
|
|
2209
|
+
*
|
|
2210
|
+
* Walker.run("BTCUSDT", {
|
|
2211
|
+
* walkerName: "my-walker",
|
|
2212
|
+
* exchangeName: "binance",
|
|
2213
|
+
* frameName: "1d-backtest"
|
|
2214
|
+
* });
|
|
2215
|
+
*
|
|
2216
|
+
* // Cancel if needed before event fires
|
|
2217
|
+
* cancel();
|
|
2218
|
+
* ```
|
|
2219
|
+
*/
|
|
2220
|
+
declare function listenWalkerOnce(filterFn: (event: WalkerContract) => boolean, fn: (event: WalkerContract) => void): () => void;
|
|
2221
|
+
/**
|
|
2222
|
+
* Subscribes to walker completion events with queued async processing.
|
|
2223
|
+
*
|
|
2224
|
+
* Emits when Walker.run() completes testing all strategies.
|
|
2225
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2226
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2227
|
+
*
|
|
2228
|
+
* @param fn - Callback function to handle walker completion event
|
|
2229
|
+
* @returns Unsubscribe function to stop listening to events
|
|
2230
|
+
*
|
|
2231
|
+
* @example
|
|
2232
|
+
* ```typescript
|
|
2233
|
+
* import { listenWalkerComplete, Walker } from "backtest-kit";
|
|
2234
|
+
*
|
|
2235
|
+
* const unsubscribe = listenWalkerComplete((results) => {
|
|
2236
|
+
* console.log(`Walker ${results.walkerName} completed!`);
|
|
2237
|
+
* console.log(`Best strategy: ${results.bestStrategy}`);
|
|
2238
|
+
* console.log(`Best ${results.metric}: ${results.bestMetric}`);
|
|
2239
|
+
* console.log(`Tested ${results.totalStrategies} strategies`);
|
|
2240
|
+
* });
|
|
2241
|
+
*
|
|
2242
|
+
* Walker.run("BTCUSDT", {
|
|
2243
|
+
* walkerName: "my-walker",
|
|
2244
|
+
* exchangeName: "binance",
|
|
2245
|
+
* frameName: "1d-backtest"
|
|
2246
|
+
* });
|
|
2247
|
+
*
|
|
2248
|
+
* // Later: stop listening
|
|
2249
|
+
* unsubscribe();
|
|
2250
|
+
* ```
|
|
2251
|
+
*/
|
|
2252
|
+
declare function listenWalkerComplete(fn: (event: IWalkerResults) => void): () => void;
|
|
2253
|
+
/**
|
|
2254
|
+
* Subscribes to risk validation errors with queued async processing.
|
|
2255
|
+
*
|
|
2256
|
+
* Emits when risk validation functions throw errors during signal checking.
|
|
2257
|
+
* Useful for debugging and monitoring risk validation failures.
|
|
2258
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2259
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2260
|
+
*
|
|
2261
|
+
* @param fn - Callback function to handle validation errors
|
|
2262
|
+
* @returns Unsubscribe function to stop listening to events
|
|
2263
|
+
*
|
|
2264
|
+
* @example
|
|
2265
|
+
* ```typescript
|
|
2266
|
+
* import { listenValidation } from "./function/event";
|
|
2267
|
+
*
|
|
2268
|
+
* const unsubscribe = listenValidation((error) => {
|
|
2269
|
+
* console.error("Risk validation error:", error.message);
|
|
2270
|
+
* // Log to monitoring service for debugging
|
|
2271
|
+
* });
|
|
2272
|
+
*
|
|
2273
|
+
* // Later: stop listening
|
|
2274
|
+
* unsubscribe();
|
|
2275
|
+
* ```
|
|
2276
|
+
*/
|
|
2277
|
+
declare function listenValidation(fn: (error: Error) => void): () => void;
|
|
1159
2278
|
|
|
1160
2279
|
/**
|
|
1161
2280
|
* Fetches historical candle data from the registered exchange.
|
|
@@ -1259,187 +2378,58 @@ declare function getDate(): Promise<Date>;
|
|
|
1259
2378
|
declare function getMode(): Promise<"backtest" | "live">;
|
|
1260
2379
|
|
|
1261
2380
|
/**
|
|
1262
|
-
*
|
|
1263
|
-
*
|
|
1264
|
-
* All numeric values are null if calculation is unsafe (NaN, Infinity, etc).
|
|
1265
|
-
* Provides comprehensive metrics for strategy performance analysis.
|
|
1266
|
-
*
|
|
1267
|
-
* @example
|
|
1268
|
-
* ```typescript
|
|
1269
|
-
* const stats = await Backtest.getData("my-strategy");
|
|
1270
|
-
*
|
|
1271
|
-
* console.log(`Total signals: ${stats.totalSignals}`);
|
|
1272
|
-
* console.log(`Win rate: ${stats.winRate}%`);
|
|
1273
|
-
* console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
|
|
1274
|
-
*
|
|
1275
|
-
* // Access raw signal data
|
|
1276
|
-
* stats.signalList.forEach(signal => {
|
|
1277
|
-
* console.log(`Signal ${signal.signal.id}: ${signal.pnl.pnlPercentage}%`);
|
|
1278
|
-
* });
|
|
1279
|
-
* ```
|
|
2381
|
+
* Portfolio heatmap statistics for a single symbol.
|
|
2382
|
+
* Aggregated metrics across all strategies for one trading pair.
|
|
1280
2383
|
*/
|
|
1281
|
-
interface
|
|
1282
|
-
/**
|
|
1283
|
-
|
|
1284
|
-
/** Total
|
|
1285
|
-
|
|
1286
|
-
/**
|
|
2384
|
+
interface IHeatmapRow {
|
|
2385
|
+
/** Trading pair symbol (e.g., "BTCUSDT") */
|
|
2386
|
+
symbol: string;
|
|
2387
|
+
/** Total profit/loss percentage across all closed trades */
|
|
2388
|
+
totalPnl: number | null;
|
|
2389
|
+
/** Risk-adjusted return (Sharpe Ratio) */
|
|
2390
|
+
sharpeRatio: number | null;
|
|
2391
|
+
/** Maximum drawdown percentage (largest peak-to-trough decline) */
|
|
2392
|
+
maxDrawdown: number | null;
|
|
2393
|
+
/** Total number of closed trades */
|
|
2394
|
+
totalTrades: number;
|
|
2395
|
+
/** Number of winning trades */
|
|
1287
2396
|
winCount: number;
|
|
1288
|
-
/** Number of losing
|
|
2397
|
+
/** Number of losing trades */
|
|
1289
2398
|
lossCount: number;
|
|
1290
|
-
/** Win rate
|
|
2399
|
+
/** Win rate percentage */
|
|
1291
2400
|
winRate: number | null;
|
|
1292
|
-
/** Average PNL per
|
|
2401
|
+
/** Average PNL per trade */
|
|
1293
2402
|
avgPnl: number | null;
|
|
1294
|
-
/**
|
|
1295
|
-
totalPnl: number | null;
|
|
1296
|
-
/** Standard deviation of returns (volatility metric), null if unsafe. Lower is better. */
|
|
2403
|
+
/** Standard deviation of PNL */
|
|
1297
2404
|
stdDev: number | null;
|
|
1298
|
-
/**
|
|
1299
|
-
|
|
1300
|
-
/**
|
|
1301
|
-
|
|
1302
|
-
/**
|
|
1303
|
-
|
|
1304
|
-
/**
|
|
1305
|
-
|
|
2405
|
+
/** Profit factor: sum of wins / sum of losses */
|
|
2406
|
+
profitFactor: number | null;
|
|
2407
|
+
/** Average profit percentage on winning trades */
|
|
2408
|
+
avgWin: number | null;
|
|
2409
|
+
/** Average loss percentage on losing trades */
|
|
2410
|
+
avgLoss: number | null;
|
|
2411
|
+
/** Maximum consecutive winning trades */
|
|
2412
|
+
maxWinStreak: number;
|
|
2413
|
+
/** Maximum consecutive losing trades */
|
|
2414
|
+
maxLossStreak: number;
|
|
2415
|
+
/** Expectancy: (winRate * avgWin) - (lossRate * avgLoss) */
|
|
2416
|
+
expectancy: number | null;
|
|
1306
2417
|
}
|
|
1307
2418
|
/**
|
|
1308
|
-
*
|
|
1309
|
-
*
|
|
1310
|
-
* Features:
|
|
1311
|
-
* - Listens to signal events via onTick callback
|
|
1312
|
-
* - Accumulates closed signals per strategy using memoized storage
|
|
1313
|
-
* - Generates markdown tables with detailed signal information
|
|
1314
|
-
* - Saves reports to disk in logs/backtest/{strategyName}.md
|
|
1315
|
-
*
|
|
1316
|
-
* @example
|
|
1317
|
-
* ```typescript
|
|
1318
|
-
* const service = new BacktestMarkdownService();
|
|
1319
|
-
*
|
|
1320
|
-
* // Add to strategy callbacks
|
|
1321
|
-
* addStrategy({
|
|
1322
|
-
* strategyName: "my-strategy",
|
|
1323
|
-
* callbacks: {
|
|
1324
|
-
* onTick: (symbol, result, backtest) => {
|
|
1325
|
-
* service.tick(result);
|
|
1326
|
-
* }
|
|
1327
|
-
* }
|
|
1328
|
-
* });
|
|
1329
|
-
*
|
|
1330
|
-
* // After backtest, generate and save report
|
|
1331
|
-
* await service.saveReport("my-strategy");
|
|
1332
|
-
* ```
|
|
2419
|
+
* Portfolio heatmap statistics structure.
|
|
2420
|
+
* Contains aggregated data for all symbols in the portfolio.
|
|
1333
2421
|
*/
|
|
1334
|
-
|
|
1335
|
-
/**
|
|
1336
|
-
|
|
1337
|
-
/**
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
*
|
|
1346
|
-
* Only processes closed signals - opened signals are ignored.
|
|
1347
|
-
*
|
|
1348
|
-
* @param data - Tick result from strategy execution (opened or closed)
|
|
1349
|
-
*
|
|
1350
|
-
* @example
|
|
1351
|
-
* ```typescript
|
|
1352
|
-
* const service = new BacktestMarkdownService();
|
|
1353
|
-
*
|
|
1354
|
-
* callbacks: {
|
|
1355
|
-
* onTick: (symbol, result, backtest) => {
|
|
1356
|
-
* service.tick(result);
|
|
1357
|
-
* }
|
|
1358
|
-
* }
|
|
1359
|
-
* ```
|
|
1360
|
-
*/
|
|
1361
|
-
private tick;
|
|
1362
|
-
/**
|
|
1363
|
-
* Gets statistical data from all closed signals for a strategy.
|
|
1364
|
-
* Delegates to ReportStorage.getData().
|
|
1365
|
-
*
|
|
1366
|
-
* @param strategyName - Strategy name to get data for
|
|
1367
|
-
* @returns Statistical data object with all metrics
|
|
1368
|
-
*
|
|
1369
|
-
* @example
|
|
1370
|
-
* ```typescript
|
|
1371
|
-
* const service = new BacktestMarkdownService();
|
|
1372
|
-
* const stats = await service.getData("my-strategy");
|
|
1373
|
-
* console.log(stats.sharpeRatio, stats.winRate);
|
|
1374
|
-
* ```
|
|
1375
|
-
*/
|
|
1376
|
-
getData: (strategyName: StrategyName) => Promise<BacktestStatistics>;
|
|
1377
|
-
/**
|
|
1378
|
-
* Generates markdown report with all closed signals for a strategy.
|
|
1379
|
-
* Delegates to ReportStorage.generateReport().
|
|
1380
|
-
*
|
|
1381
|
-
* @param strategyName - Strategy name to generate report for
|
|
1382
|
-
* @returns Markdown formatted report string with table of all closed signals
|
|
1383
|
-
*
|
|
1384
|
-
* @example
|
|
1385
|
-
* ```typescript
|
|
1386
|
-
* const service = new BacktestMarkdownService();
|
|
1387
|
-
* const markdown = await service.getReport("my-strategy");
|
|
1388
|
-
* console.log(markdown);
|
|
1389
|
-
* ```
|
|
1390
|
-
*/
|
|
1391
|
-
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
1392
|
-
/**
|
|
1393
|
-
* Saves strategy report to disk.
|
|
1394
|
-
* Creates directory if it doesn't exist.
|
|
1395
|
-
* Delegates to ReportStorage.dump().
|
|
1396
|
-
*
|
|
1397
|
-
* @param strategyName - Strategy name to save report for
|
|
1398
|
-
* @param path - Directory path to save report (default: "./logs/backtest")
|
|
1399
|
-
*
|
|
1400
|
-
* @example
|
|
1401
|
-
* ```typescript
|
|
1402
|
-
* const service = new BacktestMarkdownService();
|
|
1403
|
-
*
|
|
1404
|
-
* // Save to default path: ./logs/backtest/my-strategy.md
|
|
1405
|
-
* await service.dump("my-strategy");
|
|
1406
|
-
*
|
|
1407
|
-
* // Save to custom path: ./custom/path/my-strategy.md
|
|
1408
|
-
* await service.dump("my-strategy", "./custom/path");
|
|
1409
|
-
* ```
|
|
1410
|
-
*/
|
|
1411
|
-
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
1412
|
-
/**
|
|
1413
|
-
* Clears accumulated signal data from storage.
|
|
1414
|
-
* If strategyName is provided, clears only that strategy's data.
|
|
1415
|
-
* If strategyName is omitted, clears all strategies' data.
|
|
1416
|
-
*
|
|
1417
|
-
* @param strategyName - Optional strategy name to clear specific strategy data
|
|
1418
|
-
*
|
|
1419
|
-
* @example
|
|
1420
|
-
* ```typescript
|
|
1421
|
-
* const service = new BacktestMarkdownService();
|
|
1422
|
-
*
|
|
1423
|
-
* // Clear specific strategy data
|
|
1424
|
-
* await service.clear("my-strategy");
|
|
1425
|
-
*
|
|
1426
|
-
* // Clear all strategies' data
|
|
1427
|
-
* await service.clear();
|
|
1428
|
-
* ```
|
|
1429
|
-
*/
|
|
1430
|
-
clear: (strategyName?: StrategyName) => Promise<void>;
|
|
1431
|
-
/**
|
|
1432
|
-
* Initializes the service by subscribing to backtest signal events.
|
|
1433
|
-
* Uses singleshot to ensure initialization happens only once.
|
|
1434
|
-
* Automatically called on first use.
|
|
1435
|
-
*
|
|
1436
|
-
* @example
|
|
1437
|
-
* ```typescript
|
|
1438
|
-
* const service = new BacktestMarkdownService();
|
|
1439
|
-
* await service.init(); // Subscribe to backtest events
|
|
1440
|
-
* ```
|
|
1441
|
-
*/
|
|
1442
|
-
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
2422
|
+
interface IHeatmapStatistics {
|
|
2423
|
+
/** Array of symbol statistics */
|
|
2424
|
+
symbols: IHeatmapRow[];
|
|
2425
|
+
/** Total number of symbols tracked */
|
|
2426
|
+
totalSymbols: number;
|
|
2427
|
+
/** Portfolio-wide total PNL */
|
|
2428
|
+
portfolioTotalPnl: number | null;
|
|
2429
|
+
/** Portfolio-wide Sharpe Ratio */
|
|
2430
|
+
portfolioSharpeRatio: number | null;
|
|
2431
|
+
/** Portfolio-wide total trades */
|
|
2432
|
+
portfolioTotalTrades: number;
|
|
1443
2433
|
}
|
|
1444
2434
|
|
|
1445
2435
|
/**
|
|
@@ -1692,6 +2682,12 @@ interface MetricStats {
|
|
|
1692
2682
|
p95: number;
|
|
1693
2683
|
/** 99th percentile duration (ms) */
|
|
1694
2684
|
p99: number;
|
|
2685
|
+
/** Average wait time between events (ms) */
|
|
2686
|
+
avgWaitTime: number;
|
|
2687
|
+
/** Minimum wait time between events (ms) */
|
|
2688
|
+
minWaitTime: number;
|
|
2689
|
+
/** Maximum wait time between events (ms) */
|
|
2690
|
+
maxWaitTime: number;
|
|
1695
2691
|
}
|
|
1696
2692
|
/**
|
|
1697
2693
|
* Performance statistics aggregated by strategy.
|
|
@@ -1781,28 +2777,172 @@ declare class PerformanceMarkdownService {
|
|
|
1781
2777
|
/**
|
|
1782
2778
|
* Saves performance report to disk.
|
|
1783
2779
|
*
|
|
1784
|
-
* @param strategyName - Strategy name to save report for
|
|
1785
|
-
* @param path - Directory path to save report
|
|
2780
|
+
* @param strategyName - Strategy name to save report for
|
|
2781
|
+
* @param path - Directory path to save report
|
|
2782
|
+
*
|
|
2783
|
+
* @example
|
|
2784
|
+
* ```typescript
|
|
2785
|
+
* // Save to default path: ./logs/performance/my-strategy.md
|
|
2786
|
+
* await performanceService.dump("my-strategy");
|
|
2787
|
+
*
|
|
2788
|
+
* // Save to custom path
|
|
2789
|
+
* await performanceService.dump("my-strategy", "./custom/path");
|
|
2790
|
+
* ```
|
|
2791
|
+
*/
|
|
2792
|
+
dump: (strategyName: string, path?: string) => Promise<void>;
|
|
2793
|
+
/**
|
|
2794
|
+
* Clears accumulated performance data from storage.
|
|
2795
|
+
*
|
|
2796
|
+
* @param strategyName - Optional strategy name to clear specific strategy data
|
|
2797
|
+
*/
|
|
2798
|
+
clear: (strategyName?: string) => Promise<void>;
|
|
2799
|
+
/**
|
|
2800
|
+
* Initializes the service by subscribing to performance events.
|
|
2801
|
+
* Uses singleshot to ensure initialization happens only once.
|
|
2802
|
+
*/
|
|
2803
|
+
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
/**
|
|
2807
|
+
* Alias for walker statistics result interface.
|
|
2808
|
+
* Used for clarity in markdown service context.
|
|
2809
|
+
*
|
|
2810
|
+
*/
|
|
2811
|
+
type WalkerStatistics = IWalkerResults;
|
|
2812
|
+
/**
|
|
2813
|
+
* Service for generating and saving walker markdown reports.
|
|
2814
|
+
*
|
|
2815
|
+
* Features:
|
|
2816
|
+
* - Listens to walker events via tick callback
|
|
2817
|
+
* - Accumulates strategy results per walker using memoized storage
|
|
2818
|
+
* - Generates markdown tables with detailed strategy comparison
|
|
2819
|
+
* - Saves reports to disk in logs/walker/{walkerName}.md
|
|
2820
|
+
*
|
|
2821
|
+
* @example
|
|
2822
|
+
* ```typescript
|
|
2823
|
+
* const service = new WalkerMarkdownService();
|
|
2824
|
+
* const results = await service.getData("my-walker");
|
|
2825
|
+
* await service.dump("my-walker");
|
|
2826
|
+
* ```
|
|
2827
|
+
*/
|
|
2828
|
+
declare class WalkerMarkdownService {
|
|
2829
|
+
/** Logger service for debug output */
|
|
2830
|
+
private readonly loggerService;
|
|
2831
|
+
/**
|
|
2832
|
+
* Memoized function to get or create ReportStorage for a walker.
|
|
2833
|
+
* Each walker gets its own isolated storage instance.
|
|
2834
|
+
*/
|
|
2835
|
+
private getStorage;
|
|
2836
|
+
/**
|
|
2837
|
+
* Processes walker progress events and accumulates strategy results.
|
|
2838
|
+
* Should be called from walkerEmitter.
|
|
2839
|
+
*
|
|
2840
|
+
* @param data - Walker contract from walker execution
|
|
2841
|
+
*
|
|
2842
|
+
* @example
|
|
2843
|
+
* ```typescript
|
|
2844
|
+
* const service = new WalkerMarkdownService();
|
|
2845
|
+
* walkerEmitter.subscribe((data) => service.tick(data));
|
|
2846
|
+
* ```
|
|
2847
|
+
*/
|
|
2848
|
+
private tick;
|
|
2849
|
+
/**
|
|
2850
|
+
* Gets walker results data from all strategy results.
|
|
2851
|
+
* Delegates to ReportStorage.getData().
|
|
2852
|
+
*
|
|
2853
|
+
* @param walkerName - Walker name to get data for
|
|
2854
|
+
* @param symbol - Trading symbol
|
|
2855
|
+
* @param metric - Metric being optimized
|
|
2856
|
+
* @param context - Context with exchangeName and frameName
|
|
2857
|
+
* @returns Walker results data object with all metrics
|
|
2858
|
+
*
|
|
2859
|
+
* @example
|
|
2860
|
+
* ```typescript
|
|
2861
|
+
* const service = new WalkerMarkdownService();
|
|
2862
|
+
* const results = await service.getData("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" });
|
|
2863
|
+
* console.log(results.bestStrategy, results.bestMetric);
|
|
2864
|
+
* ```
|
|
2865
|
+
*/
|
|
2866
|
+
getData: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2867
|
+
exchangeName: string;
|
|
2868
|
+
frameName: string;
|
|
2869
|
+
}) => Promise<IWalkerResults>;
|
|
2870
|
+
/**
|
|
2871
|
+
* Generates markdown report with all strategy results for a walker.
|
|
2872
|
+
* Delegates to ReportStorage.getReport().
|
|
2873
|
+
*
|
|
2874
|
+
* @param walkerName - Walker name to generate report for
|
|
2875
|
+
* @param symbol - Trading symbol
|
|
2876
|
+
* @param metric - Metric being optimized
|
|
2877
|
+
* @param context - Context with exchangeName and frameName
|
|
2878
|
+
* @returns Markdown formatted report string
|
|
2879
|
+
*
|
|
2880
|
+
* @example
|
|
2881
|
+
* ```typescript
|
|
2882
|
+
* const service = new WalkerMarkdownService();
|
|
2883
|
+
* const markdown = await service.getReport("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" });
|
|
2884
|
+
* console.log(markdown);
|
|
2885
|
+
* ```
|
|
2886
|
+
*/
|
|
2887
|
+
getReport: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2888
|
+
exchangeName: string;
|
|
2889
|
+
frameName: string;
|
|
2890
|
+
}) => Promise<string>;
|
|
2891
|
+
/**
|
|
2892
|
+
* Saves walker report to disk.
|
|
2893
|
+
* Creates directory if it doesn't exist.
|
|
2894
|
+
* Delegates to ReportStorage.dump().
|
|
2895
|
+
*
|
|
2896
|
+
* @param walkerName - Walker name to save report for
|
|
2897
|
+
* @param symbol - Trading symbol
|
|
2898
|
+
* @param metric - Metric being optimized
|
|
2899
|
+
* @param context - Context with exchangeName and frameName
|
|
2900
|
+
* @param path - Directory path to save report (default: "./logs/walker")
|
|
1786
2901
|
*
|
|
1787
2902
|
* @example
|
|
1788
2903
|
* ```typescript
|
|
1789
|
-
*
|
|
1790
|
-
* await performanceService.dump("my-strategy");
|
|
2904
|
+
* const service = new WalkerMarkdownService();
|
|
1791
2905
|
*
|
|
1792
|
-
* // Save to
|
|
1793
|
-
* await
|
|
2906
|
+
* // Save to default path: ./logs/walker/my-walker.md
|
|
2907
|
+
* await service.dump("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" });
|
|
2908
|
+
*
|
|
2909
|
+
* // Save to custom path: ./custom/path/my-walker.md
|
|
2910
|
+
* await service.dump("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" }, "./custom/path");
|
|
1794
2911
|
* ```
|
|
1795
2912
|
*/
|
|
1796
|
-
dump: (
|
|
2913
|
+
dump: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2914
|
+
exchangeName: string;
|
|
2915
|
+
frameName: string;
|
|
2916
|
+
}, path?: string) => Promise<void>;
|
|
1797
2917
|
/**
|
|
1798
|
-
* Clears accumulated
|
|
2918
|
+
* Clears accumulated result data from storage.
|
|
2919
|
+
* If walkerName is provided, clears only that walker's data.
|
|
2920
|
+
* If walkerName is omitted, clears all walkers' data.
|
|
1799
2921
|
*
|
|
1800
|
-
* @param
|
|
2922
|
+
* @param walkerName - Optional walker name to clear specific walker data
|
|
2923
|
+
*
|
|
2924
|
+
* @example
|
|
2925
|
+
* ```typescript
|
|
2926
|
+
* const service = new WalkerMarkdownService();
|
|
2927
|
+
*
|
|
2928
|
+
* // Clear specific walker data
|
|
2929
|
+
* await service.clear("my-walker");
|
|
2930
|
+
*
|
|
2931
|
+
* // Clear all walkers' data
|
|
2932
|
+
* await service.clear();
|
|
2933
|
+
* ```
|
|
1801
2934
|
*/
|
|
1802
|
-
clear: (
|
|
2935
|
+
clear: (walkerName?: WalkerName) => Promise<void>;
|
|
1803
2936
|
/**
|
|
1804
|
-
* Initializes the service by subscribing to
|
|
2937
|
+
* Initializes the service by subscribing to walker events.
|
|
1805
2938
|
* Uses singleshot to ensure initialization happens only once.
|
|
2939
|
+
* Automatically called on first use.
|
|
2940
|
+
*
|
|
2941
|
+
* @example
|
|
2942
|
+
* ```typescript
|
|
2943
|
+
* const service = new WalkerMarkdownService();
|
|
2944
|
+
* await service.init(); // Subscribe to walker events
|
|
2945
|
+
* ```
|
|
1806
2946
|
*/
|
|
1807
2947
|
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
1808
2948
|
}
|
|
@@ -2035,6 +3175,79 @@ declare class PersistSignalUtils {
|
|
|
2035
3175
|
* ```
|
|
2036
3176
|
*/
|
|
2037
3177
|
declare const PersistSignalAdaper: PersistSignalUtils;
|
|
3178
|
+
/**
|
|
3179
|
+
* Type for persisted risk positions data.
|
|
3180
|
+
* Stores Map entries as array of [key, value] tuples for JSON serialization.
|
|
3181
|
+
*/
|
|
3182
|
+
type RiskData = Array<[string, IRiskActivePosition]>;
|
|
3183
|
+
/**
|
|
3184
|
+
* Utility class for managing risk active positions persistence.
|
|
3185
|
+
*
|
|
3186
|
+
* Features:
|
|
3187
|
+
* - Memoized storage instances per risk profile
|
|
3188
|
+
* - Custom adapter support
|
|
3189
|
+
* - Atomic read/write operations for RiskData
|
|
3190
|
+
* - Crash-safe position state management
|
|
3191
|
+
*
|
|
3192
|
+
* Used by ClientRisk for live mode persistence of active positions.
|
|
3193
|
+
*/
|
|
3194
|
+
declare class PersistRiskUtils {
|
|
3195
|
+
private PersistRiskFactory;
|
|
3196
|
+
private getRiskStorage;
|
|
3197
|
+
/**
|
|
3198
|
+
* Registers a custom persistence adapter.
|
|
3199
|
+
*
|
|
3200
|
+
* @param Ctor - Custom PersistBase constructor
|
|
3201
|
+
*
|
|
3202
|
+
* @example
|
|
3203
|
+
* ```typescript
|
|
3204
|
+
* class RedisPersist extends PersistBase {
|
|
3205
|
+
* async readValue(id) { return JSON.parse(await redis.get(id)); }
|
|
3206
|
+
* async writeValue(id, entity) { await redis.set(id, JSON.stringify(entity)); }
|
|
3207
|
+
* }
|
|
3208
|
+
* PersistRiskAdapter.usePersistRiskAdapter(RedisPersist);
|
|
3209
|
+
* ```
|
|
3210
|
+
*/
|
|
3211
|
+
usePersistRiskAdapter(Ctor: TPersistBaseCtor<RiskName, RiskData>): void;
|
|
3212
|
+
/**
|
|
3213
|
+
* Reads persisted active positions for a risk profile.
|
|
3214
|
+
*
|
|
3215
|
+
* Called by ClientRisk.waitForInit() to restore state.
|
|
3216
|
+
* Returns empty Map if no positions exist.
|
|
3217
|
+
*
|
|
3218
|
+
* @param riskName - Risk profile identifier
|
|
3219
|
+
* @returns Promise resolving to Map of active positions
|
|
3220
|
+
*/
|
|
3221
|
+
readPositionData: (riskName: RiskName) => Promise<RiskData>;
|
|
3222
|
+
/**
|
|
3223
|
+
* Writes active positions to disk with atomic file writes.
|
|
3224
|
+
*
|
|
3225
|
+
* Called by ClientRisk after addSignal/removeSignal to persist state.
|
|
3226
|
+
* Uses atomic writes to prevent corruption on crashes.
|
|
3227
|
+
*
|
|
3228
|
+
* @param positions - Map of active positions
|
|
3229
|
+
* @param riskName - Risk profile identifier
|
|
3230
|
+
* @returns Promise that resolves when write is complete
|
|
3231
|
+
*/
|
|
3232
|
+
writePositionData: (riskRow: RiskData, riskName: RiskName) => Promise<void>;
|
|
3233
|
+
}
|
|
3234
|
+
/**
|
|
3235
|
+
* Global singleton instance of PersistRiskUtils.
|
|
3236
|
+
* Used by ClientRisk for active positions persistence.
|
|
3237
|
+
*
|
|
3238
|
+
* @example
|
|
3239
|
+
* ```typescript
|
|
3240
|
+
* // Custom adapter
|
|
3241
|
+
* PersistRiskAdapter.usePersistRiskAdapter(RedisPersist);
|
|
3242
|
+
*
|
|
3243
|
+
* // Read positions
|
|
3244
|
+
* const positions = await PersistRiskAdapter.readPositionData("my-risk");
|
|
3245
|
+
*
|
|
3246
|
+
* // Write positions
|
|
3247
|
+
* await PersistRiskAdapter.writePositionData(positionsMap, "my-risk");
|
|
3248
|
+
* ```
|
|
3249
|
+
*/
|
|
3250
|
+
declare const PersistRiskAdapter: PersistRiskUtils;
|
|
2038
3251
|
|
|
2039
3252
|
/**
|
|
2040
3253
|
* Utility class for backtest operations.
|
|
@@ -2274,135 +3487,534 @@ declare class LiveUtils {
|
|
|
2274
3487
|
*
|
|
2275
3488
|
* @example
|
|
2276
3489
|
* ```typescript
|
|
2277
|
-
* import { Live } from "./classes/Live";
|
|
3490
|
+
* import { Live } from "./classes/Live";
|
|
3491
|
+
*
|
|
3492
|
+
* for await (const result of Live.run("BTCUSDT", {
|
|
3493
|
+
* strategyName: "my-strategy",
|
|
3494
|
+
* exchangeName: "my-exchange",
|
|
3495
|
+
* })) {
|
|
3496
|
+
* console.log("Result:", result.action);
|
|
3497
|
+
* }
|
|
3498
|
+
* ```
|
|
3499
|
+
*/
|
|
3500
|
+
declare const Live: LiveUtils;
|
|
3501
|
+
|
|
3502
|
+
/**
|
|
3503
|
+
* Performance class provides static methods for performance metrics analysis.
|
|
3504
|
+
*
|
|
3505
|
+
* Features:
|
|
3506
|
+
* - Get aggregated performance statistics by strategy
|
|
3507
|
+
* - Generate markdown reports with bottleneck analysis
|
|
3508
|
+
* - Save reports to disk
|
|
3509
|
+
* - Clear accumulated metrics
|
|
3510
|
+
*
|
|
3511
|
+
* @example
|
|
3512
|
+
* ```typescript
|
|
3513
|
+
* import { Performance, listenPerformance } from "backtest-kit";
|
|
3514
|
+
*
|
|
3515
|
+
* // Subscribe to performance events
|
|
3516
|
+
* listenPerformance((event) => {
|
|
3517
|
+
* console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
3518
|
+
* });
|
|
3519
|
+
*
|
|
3520
|
+
* // Run backtest...
|
|
3521
|
+
*
|
|
3522
|
+
* // Get aggregated statistics
|
|
3523
|
+
* const stats = await Performance.getData("my-strategy");
|
|
3524
|
+
* console.log("Total time:", stats.totalDuration);
|
|
3525
|
+
* console.log("Slowest operations:", Object.values(stats.metricStats)
|
|
3526
|
+
* .sort((a, b) => b.avgDuration - a.avgDuration)
|
|
3527
|
+
* .slice(0, 5));
|
|
3528
|
+
*
|
|
3529
|
+
* // Generate and save report
|
|
3530
|
+
* await Performance.dump("my-strategy");
|
|
3531
|
+
* ```
|
|
3532
|
+
*/
|
|
3533
|
+
declare class Performance {
|
|
3534
|
+
/**
|
|
3535
|
+
* Gets aggregated performance statistics for a strategy.
|
|
3536
|
+
*
|
|
3537
|
+
* Returns detailed metrics grouped by operation type:
|
|
3538
|
+
* - Count, total duration, average, min, max
|
|
3539
|
+
* - Standard deviation for volatility
|
|
3540
|
+
* - Percentiles (median, P95, P99) for outlier detection
|
|
3541
|
+
*
|
|
3542
|
+
* @param strategyName - Strategy name to analyze
|
|
3543
|
+
* @returns Performance statistics with aggregated metrics
|
|
3544
|
+
*
|
|
3545
|
+
* @example
|
|
3546
|
+
* ```typescript
|
|
3547
|
+
* const stats = await Performance.getData("my-strategy");
|
|
3548
|
+
*
|
|
3549
|
+
* // Find slowest operation type
|
|
3550
|
+
* const slowest = Object.values(stats.metricStats)
|
|
3551
|
+
* .sort((a, b) => b.avgDuration - a.avgDuration)[0];
|
|
3552
|
+
* console.log(`Slowest: ${slowest.metricType} (${slowest.avgDuration.toFixed(2)}ms avg)`);
|
|
3553
|
+
*
|
|
3554
|
+
* // Check for outliers
|
|
3555
|
+
* for (const metric of Object.values(stats.metricStats)) {
|
|
3556
|
+
* if (metric.p99 > metric.avgDuration * 5) {
|
|
3557
|
+
* console.warn(`High variance in ${metric.metricType}: P99=${metric.p99}ms, Avg=${metric.avgDuration}ms`);
|
|
3558
|
+
* }
|
|
3559
|
+
* }
|
|
3560
|
+
* ```
|
|
3561
|
+
*/
|
|
3562
|
+
static getData(strategyName: string): Promise<PerformanceStatistics>;
|
|
3563
|
+
/**
|
|
3564
|
+
* Generates markdown report with performance analysis.
|
|
3565
|
+
*
|
|
3566
|
+
* Report includes:
|
|
3567
|
+
* - Time distribution across operation types
|
|
3568
|
+
* - Detailed metrics table with statistics
|
|
3569
|
+
* - Percentile analysis for bottleneck detection
|
|
3570
|
+
*
|
|
3571
|
+
* @param strategyName - Strategy name to generate report for
|
|
3572
|
+
* @returns Markdown formatted report string
|
|
3573
|
+
*
|
|
3574
|
+
* @example
|
|
3575
|
+
* ```typescript
|
|
3576
|
+
* const markdown = await Performance.getReport("my-strategy");
|
|
3577
|
+
* console.log(markdown);
|
|
3578
|
+
*
|
|
3579
|
+
* // Or save to file
|
|
3580
|
+
* import fs from "fs/promises";
|
|
3581
|
+
* await fs.writeFile("performance-report.md", markdown);
|
|
3582
|
+
* ```
|
|
3583
|
+
*/
|
|
3584
|
+
static getReport(strategyName: string): Promise<string>;
|
|
3585
|
+
/**
|
|
3586
|
+
* Saves performance report to disk.
|
|
3587
|
+
*
|
|
3588
|
+
* Creates directory if it doesn't exist.
|
|
3589
|
+
* Default path: ./logs/performance/{strategyName}.md
|
|
3590
|
+
*
|
|
3591
|
+
* @param strategyName - Strategy name to save report for
|
|
3592
|
+
* @param path - Optional custom directory path
|
|
3593
|
+
*
|
|
3594
|
+
* @example
|
|
3595
|
+
* ```typescript
|
|
3596
|
+
* // Save to default path: ./logs/performance/my-strategy.md
|
|
3597
|
+
* await Performance.dump("my-strategy");
|
|
3598
|
+
*
|
|
3599
|
+
* // Save to custom path: ./reports/perf/my-strategy.md
|
|
3600
|
+
* await Performance.dump("my-strategy", "./reports/perf");
|
|
3601
|
+
* ```
|
|
3602
|
+
*/
|
|
3603
|
+
static dump(strategyName: string, path?: string): Promise<void>;
|
|
3604
|
+
/**
|
|
3605
|
+
* Clears accumulated performance metrics from memory.
|
|
3606
|
+
*
|
|
3607
|
+
* @param strategyName - Optional strategy name to clear specific strategy's metrics
|
|
3608
|
+
*
|
|
3609
|
+
* @example
|
|
3610
|
+
* ```typescript
|
|
3611
|
+
* // Clear specific strategy metrics
|
|
3612
|
+
* await Performance.clear("my-strategy");
|
|
3613
|
+
*
|
|
3614
|
+
* // Clear all metrics for all strategies
|
|
3615
|
+
* await Performance.clear();
|
|
3616
|
+
* ```
|
|
3617
|
+
*/
|
|
3618
|
+
static clear(strategyName?: string): Promise<void>;
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
/**
|
|
3622
|
+
* Utility class for walker operations.
|
|
3623
|
+
*
|
|
3624
|
+
* Provides simplified access to walkerGlobalService.run() with logging.
|
|
3625
|
+
* Automatically pulls exchangeName and frameName from walker schema.
|
|
3626
|
+
* Exported as singleton instance for convenient usage.
|
|
3627
|
+
*
|
|
3628
|
+
* @example
|
|
3629
|
+
* ```typescript
|
|
3630
|
+
* import { Walker } from "./classes/Walker";
|
|
3631
|
+
*
|
|
3632
|
+
* for await (const result of Walker.run("BTCUSDT", {
|
|
3633
|
+
* walkerName: "my-walker"
|
|
3634
|
+
* })) {
|
|
3635
|
+
* console.log("Progress:", result.strategiesTested, "/", result.totalStrategies);
|
|
3636
|
+
* console.log("Best strategy:", result.bestStrategy, result.bestMetric);
|
|
3637
|
+
* }
|
|
3638
|
+
* ```
|
|
3639
|
+
*/
|
|
3640
|
+
declare class WalkerUtils {
|
|
3641
|
+
/**
|
|
3642
|
+
* Runs walker comparison for a symbol with context propagation.
|
|
3643
|
+
*
|
|
3644
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3645
|
+
* @param context - Execution context with walker name
|
|
3646
|
+
* @returns Async generator yielding progress updates after each strategy
|
|
3647
|
+
*/
|
|
3648
|
+
run: (symbol: string, context: {
|
|
3649
|
+
walkerName: string;
|
|
3650
|
+
}) => AsyncGenerator<WalkerContract, any, any>;
|
|
3651
|
+
/**
|
|
3652
|
+
* Runs walker comparison in background without yielding results.
|
|
3653
|
+
*
|
|
3654
|
+
* Consumes all walker progress updates internally without exposing them.
|
|
3655
|
+
* Useful for running walker comparison for side effects only (callbacks, logging).
|
|
3656
|
+
*
|
|
3657
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3658
|
+
* @param context - Execution context with walker name
|
|
3659
|
+
* @returns Cancellation closure
|
|
3660
|
+
*
|
|
3661
|
+
* @example
|
|
3662
|
+
* ```typescript
|
|
3663
|
+
* // Run walker silently, only callbacks will fire
|
|
3664
|
+
* await Walker.background("BTCUSDT", {
|
|
3665
|
+
* walkerName: "my-walker"
|
|
3666
|
+
* });
|
|
3667
|
+
* console.log("Walker comparison completed");
|
|
3668
|
+
* ```
|
|
3669
|
+
*/
|
|
3670
|
+
background: (symbol: string, context: {
|
|
3671
|
+
walkerName: string;
|
|
3672
|
+
}) => () => void;
|
|
3673
|
+
/**
|
|
3674
|
+
* Gets walker results data from all strategy comparisons.
|
|
3675
|
+
*
|
|
3676
|
+
* @param symbol - Trading symbol
|
|
3677
|
+
* @param walkerName - Walker name to get data for
|
|
3678
|
+
* @returns Promise resolving to walker results data object
|
|
3679
|
+
*
|
|
3680
|
+
* @example
|
|
3681
|
+
* ```typescript
|
|
3682
|
+
* const results = await Walker.getData("BTCUSDT", "my-walker");
|
|
3683
|
+
* console.log(results.bestStrategy, results.bestMetric);
|
|
3684
|
+
* ```
|
|
3685
|
+
*/
|
|
3686
|
+
getData: (symbol: string, walkerName: WalkerName) => Promise<IWalkerResults>;
|
|
3687
|
+
/**
|
|
3688
|
+
* Generates markdown report with all strategy comparisons for a walker.
|
|
3689
|
+
*
|
|
3690
|
+
* @param symbol - Trading symbol
|
|
3691
|
+
* @param walkerName - Walker name to generate report for
|
|
3692
|
+
* @returns Promise resolving to markdown formatted report string
|
|
3693
|
+
*
|
|
3694
|
+
* @example
|
|
3695
|
+
* ```typescript
|
|
3696
|
+
* const markdown = await Walker.getReport("BTCUSDT", "my-walker");
|
|
3697
|
+
* console.log(markdown);
|
|
3698
|
+
* ```
|
|
3699
|
+
*/
|
|
3700
|
+
getReport: (symbol: string, walkerName: WalkerName) => Promise<string>;
|
|
3701
|
+
/**
|
|
3702
|
+
* Saves walker report to disk.
|
|
3703
|
+
*
|
|
3704
|
+
* @param symbol - Trading symbol
|
|
3705
|
+
* @param walkerName - Walker name to save report for
|
|
3706
|
+
* @param path - Optional directory path to save report (default: "./logs/walker")
|
|
3707
|
+
*
|
|
3708
|
+
* @example
|
|
3709
|
+
* ```typescript
|
|
3710
|
+
* // Save to default path: ./logs/walker/my-walker.md
|
|
3711
|
+
* await Walker.dump("BTCUSDT", "my-walker");
|
|
3712
|
+
*
|
|
3713
|
+
* // Save to custom path: ./custom/path/my-walker.md
|
|
3714
|
+
* await Walker.dump("BTCUSDT", "my-walker", "./custom/path");
|
|
3715
|
+
* ```
|
|
3716
|
+
*/
|
|
3717
|
+
dump: (symbol: string, walkerName: WalkerName, path?: string) => Promise<void>;
|
|
3718
|
+
}
|
|
3719
|
+
/**
|
|
3720
|
+
* Singleton instance of WalkerUtils for convenient walker operations.
|
|
3721
|
+
*
|
|
3722
|
+
* @example
|
|
3723
|
+
* ```typescript
|
|
3724
|
+
* import { Walker } from "./classes/Walker";
|
|
2278
3725
|
*
|
|
2279
|
-
* for await (const result of
|
|
2280
|
-
*
|
|
2281
|
-
* exchangeName: "my-exchange",
|
|
3726
|
+
* for await (const result of Walker.run("BTCUSDT", {
|
|
3727
|
+
* walkerName: "my-walker"
|
|
2282
3728
|
* })) {
|
|
2283
|
-
* console.log("
|
|
3729
|
+
* console.log("Progress:", result.strategiesTested, "/", result.totalStrategies);
|
|
3730
|
+
* console.log("Best so far:", result.bestStrategy, result.bestMetric);
|
|
2284
3731
|
* }
|
|
2285
3732
|
* ```
|
|
2286
3733
|
*/
|
|
2287
|
-
declare const
|
|
3734
|
+
declare const Walker: WalkerUtils;
|
|
2288
3735
|
|
|
2289
3736
|
/**
|
|
2290
|
-
*
|
|
3737
|
+
* Utility class for portfolio heatmap operations.
|
|
2291
3738
|
*
|
|
2292
|
-
*
|
|
2293
|
-
*
|
|
2294
|
-
*
|
|
2295
|
-
* - Save reports to disk
|
|
2296
|
-
* - Clear accumulated metrics
|
|
3739
|
+
* Provides simplified access to heatMarkdownService with logging.
|
|
3740
|
+
* Automatically aggregates statistics across all symbols per strategy.
|
|
3741
|
+
* Exported as singleton instance for convenient usage.
|
|
2297
3742
|
*
|
|
2298
3743
|
* @example
|
|
2299
3744
|
* ```typescript
|
|
2300
|
-
* import {
|
|
2301
|
-
*
|
|
2302
|
-
* // Subscribe to performance events
|
|
2303
|
-
* listenPerformance((event) => {
|
|
2304
|
-
* console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
2305
|
-
* });
|
|
3745
|
+
* import { Heat } from "backtest-kit";
|
|
2306
3746
|
*
|
|
2307
|
-
* //
|
|
3747
|
+
* // Get raw heatmap data for a strategy
|
|
3748
|
+
* const stats = await Heat.getData("my-strategy");
|
|
3749
|
+
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
2308
3750
|
*
|
|
2309
|
-
* //
|
|
2310
|
-
* const
|
|
2311
|
-
* console.log(
|
|
2312
|
-
* console.log("Slowest operations:", Object.values(stats.metricStats)
|
|
2313
|
-
* .sort((a, b) => b.avgDuration - a.avgDuration)
|
|
2314
|
-
* .slice(0, 5));
|
|
3751
|
+
* // Generate markdown report
|
|
3752
|
+
* const markdown = await Heat.getReport("my-strategy");
|
|
3753
|
+
* console.log(markdown);
|
|
2315
3754
|
*
|
|
2316
|
-
* //
|
|
2317
|
-
* await
|
|
3755
|
+
* // Save to disk
|
|
3756
|
+
* await Heat.dump("my-strategy", "./reports");
|
|
2318
3757
|
* ```
|
|
2319
3758
|
*/
|
|
2320
|
-
declare class
|
|
3759
|
+
declare class HeatUtils {
|
|
2321
3760
|
/**
|
|
2322
|
-
* Gets aggregated
|
|
3761
|
+
* Gets aggregated portfolio heatmap statistics for a strategy.
|
|
2323
3762
|
*
|
|
2324
|
-
* Returns
|
|
2325
|
-
*
|
|
2326
|
-
* - Standard deviation for volatility
|
|
2327
|
-
* - Percentiles (median, P95, P99) for outlier detection
|
|
3763
|
+
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
3764
|
+
* Data is automatically collected from all closed signals for the strategy.
|
|
2328
3765
|
*
|
|
2329
|
-
* @param strategyName - Strategy name to
|
|
2330
|
-
* @returns
|
|
3766
|
+
* @param strategyName - Strategy name to get heatmap data for
|
|
3767
|
+
* @returns Promise resolving to heatmap statistics object
|
|
2331
3768
|
*
|
|
2332
3769
|
* @example
|
|
2333
3770
|
* ```typescript
|
|
2334
|
-
* const stats = await
|
|
3771
|
+
* const stats = await Heat.getData("my-strategy");
|
|
2335
3772
|
*
|
|
2336
|
-
*
|
|
2337
|
-
*
|
|
2338
|
-
*
|
|
2339
|
-
* console.log(`Slowest: ${slowest.metricType} (${slowest.avgDuration.toFixed(2)}ms avg)`);
|
|
3773
|
+
* console.log(`Total symbols: ${stats.totalSymbols}`);
|
|
3774
|
+
* console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
|
|
3775
|
+
* console.log(`Portfolio Sharpe Ratio: ${stats.portfolioSharpeRatio}`);
|
|
2340
3776
|
*
|
|
2341
|
-
* //
|
|
2342
|
-
*
|
|
2343
|
-
*
|
|
2344
|
-
*
|
|
2345
|
-
* }
|
|
2346
|
-
* }
|
|
3777
|
+
* // Iterate through per-symbol statistics
|
|
3778
|
+
* stats.symbols.forEach(row => {
|
|
3779
|
+
* console.log(`${row.symbol}: ${row.totalPnl}% (${row.totalTrades} trades)`);
|
|
3780
|
+
* });
|
|
2347
3781
|
* ```
|
|
2348
3782
|
*/
|
|
2349
|
-
|
|
3783
|
+
getData: (strategyName: StrategyName) => Promise<IHeatmapStatistics>;
|
|
2350
3784
|
/**
|
|
2351
|
-
* Generates markdown report with
|
|
3785
|
+
* Generates markdown report with portfolio heatmap table for a strategy.
|
|
2352
3786
|
*
|
|
2353
|
-
*
|
|
2354
|
-
*
|
|
2355
|
-
* - Detailed metrics table with statistics
|
|
2356
|
-
* - Percentile analysis for bottleneck detection
|
|
3787
|
+
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
3788
|
+
* Symbols are sorted by Total PNL descending.
|
|
2357
3789
|
*
|
|
2358
|
-
* @param strategyName - Strategy name to generate report for
|
|
2359
|
-
* @returns
|
|
3790
|
+
* @param strategyName - Strategy name to generate heatmap report for
|
|
3791
|
+
* @returns Promise resolving to markdown formatted report string
|
|
2360
3792
|
*
|
|
2361
3793
|
* @example
|
|
2362
3794
|
* ```typescript
|
|
2363
|
-
* const markdown = await
|
|
3795
|
+
* const markdown = await Heat.getReport("my-strategy");
|
|
2364
3796
|
* console.log(markdown);
|
|
2365
|
-
*
|
|
2366
|
-
* //
|
|
2367
|
-
*
|
|
2368
|
-
*
|
|
3797
|
+
* // Output:
|
|
3798
|
+
* // # Portfolio Heatmap: my-strategy
|
|
3799
|
+
* //
|
|
3800
|
+
* // **Total Symbols:** 5 | **Portfolio PNL:** +45.3% | **Portfolio Sharpe:** 1.85 | **Total Trades:** 120
|
|
3801
|
+
* //
|
|
3802
|
+
* // | Symbol | Total PNL | Sharpe | Max DD | Trades |
|
|
3803
|
+
* // |--------|-----------|--------|--------|--------|
|
|
3804
|
+
* // | BTCUSDT | +15.5% | 2.10 | -2.5% | 45 |
|
|
3805
|
+
* // | ETHUSDT | +12.3% | 1.85 | -3.1% | 38 |
|
|
3806
|
+
* // ...
|
|
2369
3807
|
* ```
|
|
2370
3808
|
*/
|
|
2371
|
-
|
|
3809
|
+
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
2372
3810
|
/**
|
|
2373
|
-
* Saves
|
|
3811
|
+
* Saves heatmap report to disk for a strategy.
|
|
2374
3812
|
*
|
|
2375
3813
|
* Creates directory if it doesn't exist.
|
|
2376
|
-
* Default
|
|
3814
|
+
* Default filename: {strategyName}.md
|
|
2377
3815
|
*
|
|
2378
|
-
* @param strategyName - Strategy name to save report for
|
|
2379
|
-
* @param path - Optional
|
|
3816
|
+
* @param strategyName - Strategy name to save heatmap report for
|
|
3817
|
+
* @param path - Optional directory path to save report (default: "./logs/heatmap")
|
|
2380
3818
|
*
|
|
2381
3819
|
* @example
|
|
2382
3820
|
* ```typescript
|
|
2383
|
-
* // Save to default path: ./logs/
|
|
2384
|
-
* await
|
|
3821
|
+
* // Save to default path: ./logs/heatmap/my-strategy.md
|
|
3822
|
+
* await Heat.dump("my-strategy");
|
|
2385
3823
|
*
|
|
2386
|
-
* // Save to custom path: ./reports/
|
|
2387
|
-
* await
|
|
3824
|
+
* // Save to custom path: ./reports/my-strategy.md
|
|
3825
|
+
* await Heat.dump("my-strategy", "./reports");
|
|
2388
3826
|
* ```
|
|
2389
3827
|
*/
|
|
2390
|
-
|
|
3828
|
+
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
3829
|
+
}
|
|
3830
|
+
/**
|
|
3831
|
+
* Singleton instance of HeatUtils for convenient heatmap operations.
|
|
3832
|
+
*
|
|
3833
|
+
* @example
|
|
3834
|
+
* ```typescript
|
|
3835
|
+
* import { Heat } from "backtest-kit";
|
|
3836
|
+
*
|
|
3837
|
+
* // Strategy-specific heatmap
|
|
3838
|
+
* const stats = await Heat.getData("my-strategy");
|
|
3839
|
+
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
3840
|
+
* console.log(`Total Symbols: ${stats.totalSymbols}`);
|
|
3841
|
+
*
|
|
3842
|
+
* // Per-symbol breakdown
|
|
3843
|
+
* stats.symbols.forEach(row => {
|
|
3844
|
+
* console.log(`${row.symbol}:`);
|
|
3845
|
+
* console.log(` Total PNL: ${row.totalPnl}%`);
|
|
3846
|
+
* console.log(` Sharpe Ratio: ${row.sharpeRatio}`);
|
|
3847
|
+
* console.log(` Max Drawdown: ${row.maxDrawdown}%`);
|
|
3848
|
+
* console.log(` Trades: ${row.totalTrades}`);
|
|
3849
|
+
* });
|
|
3850
|
+
*
|
|
3851
|
+
* // Generate and save report
|
|
3852
|
+
* await Heat.dump("my-strategy", "./reports");
|
|
3853
|
+
* ```
|
|
3854
|
+
*/
|
|
3855
|
+
declare const Heat: HeatUtils;
|
|
3856
|
+
|
|
3857
|
+
/**
|
|
3858
|
+
* Utility class for position sizing calculations.
|
|
3859
|
+
*
|
|
3860
|
+
* Provides static methods for each sizing method with validation.
|
|
3861
|
+
* Each method validates that the sizing schema matches the requested method.
|
|
3862
|
+
*
|
|
3863
|
+
* @example
|
|
3864
|
+
* ```typescript
|
|
3865
|
+
* import { PositionSize } from "./classes/PositionSize";
|
|
3866
|
+
*
|
|
3867
|
+
* // Fixed percentage sizing
|
|
3868
|
+
* const quantity = await PositionSize.fixedPercentage(
|
|
3869
|
+
* "BTCUSDT",
|
|
3870
|
+
* 10000,
|
|
3871
|
+
* 50000,
|
|
3872
|
+
* 49000,
|
|
3873
|
+
* { sizingName: "conservative" }
|
|
3874
|
+
* );
|
|
3875
|
+
*
|
|
3876
|
+
* // Kelly Criterion sizing
|
|
3877
|
+
* const quantity = await PositionSize.kellyCriterion(
|
|
3878
|
+
* "BTCUSDT",
|
|
3879
|
+
* 10000,
|
|
3880
|
+
* 50000,
|
|
3881
|
+
* 0.55,
|
|
3882
|
+
* 1.5,
|
|
3883
|
+
* { sizingName: "kelly" }
|
|
3884
|
+
* );
|
|
3885
|
+
*
|
|
3886
|
+
* // ATR-based sizing
|
|
3887
|
+
* const quantity = await PositionSize.atrBased(
|
|
3888
|
+
* "BTCUSDT",
|
|
3889
|
+
* 10000,
|
|
3890
|
+
* 50000,
|
|
3891
|
+
* 500,
|
|
3892
|
+
* { sizingName: "atr-dynamic" }
|
|
3893
|
+
* );
|
|
3894
|
+
* ```
|
|
3895
|
+
*/
|
|
3896
|
+
declare class PositionSizeUtils {
|
|
2391
3897
|
/**
|
|
2392
|
-
*
|
|
3898
|
+
* Calculates position size using fixed percentage risk method.
|
|
2393
3899
|
*
|
|
2394
|
-
* @param
|
|
3900
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3901
|
+
* @param accountBalance - Current account balance
|
|
3902
|
+
* @param priceOpen - Planned entry price
|
|
3903
|
+
* @param priceStopLoss - Stop-loss price
|
|
3904
|
+
* @param context - Execution context with sizing name
|
|
3905
|
+
* @returns Promise resolving to calculated position size
|
|
3906
|
+
* @throws Error if sizing schema method is not "fixed-percentage"
|
|
3907
|
+
*/
|
|
3908
|
+
static fixedPercentage: (symbol: string, accountBalance: number, priceOpen: number, priceStopLoss: number, context: {
|
|
3909
|
+
sizingName: SizingName;
|
|
3910
|
+
}) => Promise<number>;
|
|
3911
|
+
/**
|
|
3912
|
+
* Calculates position size using Kelly Criterion method.
|
|
2395
3913
|
*
|
|
2396
|
-
* @
|
|
2397
|
-
*
|
|
2398
|
-
*
|
|
2399
|
-
*
|
|
3914
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3915
|
+
* @param accountBalance - Current account balance
|
|
3916
|
+
* @param priceOpen - Planned entry price
|
|
3917
|
+
* @param winRate - Win rate (0-1)
|
|
3918
|
+
* @param winLossRatio - Average win/loss ratio
|
|
3919
|
+
* @param context - Execution context with sizing name
|
|
3920
|
+
* @returns Promise resolving to calculated position size
|
|
3921
|
+
* @throws Error if sizing schema method is not "kelly-criterion"
|
|
3922
|
+
*/
|
|
3923
|
+
static kellyCriterion: (symbol: string, accountBalance: number, priceOpen: number, winRate: number, winLossRatio: number, context: {
|
|
3924
|
+
sizingName: SizingName;
|
|
3925
|
+
}) => Promise<number>;
|
|
3926
|
+
/**
|
|
3927
|
+
* Calculates position size using ATR-based method.
|
|
2400
3928
|
*
|
|
2401
|
-
*
|
|
2402
|
-
*
|
|
2403
|
-
*
|
|
3929
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
3930
|
+
* @param accountBalance - Current account balance
|
|
3931
|
+
* @param priceOpen - Planned entry price
|
|
3932
|
+
* @param atr - Current ATR value
|
|
3933
|
+
* @param context - Execution context with sizing name
|
|
3934
|
+
* @returns Promise resolving to calculated position size
|
|
3935
|
+
* @throws Error if sizing schema method is not "atr-based"
|
|
2404
3936
|
*/
|
|
2405
|
-
static
|
|
3937
|
+
static atrBased: (symbol: string, accountBalance: number, priceOpen: number, atr: number, context: {
|
|
3938
|
+
sizingName: SizingName;
|
|
3939
|
+
}) => Promise<number>;
|
|
3940
|
+
}
|
|
3941
|
+
declare const PositionSize: typeof PositionSizeUtils;
|
|
3942
|
+
|
|
3943
|
+
/**
|
|
3944
|
+
* Global signal emitter for all trading events (live + backtest).
|
|
3945
|
+
* Emits all signal events regardless of execution mode.
|
|
3946
|
+
*/
|
|
3947
|
+
declare const signalEmitter: Subject<IStrategyTickResult>;
|
|
3948
|
+
/**
|
|
3949
|
+
* Live trading signal emitter.
|
|
3950
|
+
* Emits only signals from live trading execution.
|
|
3951
|
+
*/
|
|
3952
|
+
declare const signalLiveEmitter: Subject<IStrategyTickResult>;
|
|
3953
|
+
/**
|
|
3954
|
+
* Backtest signal emitter.
|
|
3955
|
+
* Emits only signals from backtest execution.
|
|
3956
|
+
*/
|
|
3957
|
+
declare const signalBacktestEmitter: Subject<IStrategyTickResult>;
|
|
3958
|
+
/**
|
|
3959
|
+
* Error emitter for background execution errors.
|
|
3960
|
+
* Emits errors caught in background tasks (Live.background, Backtest.background).
|
|
3961
|
+
*/
|
|
3962
|
+
declare const errorEmitter: Subject<Error>;
|
|
3963
|
+
/**
|
|
3964
|
+
* Done emitter for live background execution completion.
|
|
3965
|
+
* Emits when live background tasks complete (Live.background).
|
|
3966
|
+
*/
|
|
3967
|
+
declare const doneLiveSubject: Subject<DoneContract>;
|
|
3968
|
+
/**
|
|
3969
|
+
* Done emitter for backtest background execution completion.
|
|
3970
|
+
* Emits when backtest background tasks complete (Backtest.background).
|
|
3971
|
+
*/
|
|
3972
|
+
declare const doneBacktestSubject: Subject<DoneContract>;
|
|
3973
|
+
/**
|
|
3974
|
+
* Done emitter for walker background execution completion.
|
|
3975
|
+
* Emits when walker background tasks complete (Walker.background).
|
|
3976
|
+
*/
|
|
3977
|
+
declare const doneWalkerSubject: Subject<DoneContract>;
|
|
3978
|
+
/**
|
|
3979
|
+
* Progress emitter for backtest execution progress.
|
|
3980
|
+
* Emits progress updates during backtest execution.
|
|
3981
|
+
*/
|
|
3982
|
+
declare const progressEmitter: Subject<ProgressContract>;
|
|
3983
|
+
/**
|
|
3984
|
+
* Performance emitter for execution metrics.
|
|
3985
|
+
* Emits performance metrics for profiling and bottleneck detection.
|
|
3986
|
+
*/
|
|
3987
|
+
declare const performanceEmitter: Subject<PerformanceContract>;
|
|
3988
|
+
/**
|
|
3989
|
+
* Walker emitter for strategy comparison progress.
|
|
3990
|
+
* Emits progress updates during walker execution (each strategy completion).
|
|
3991
|
+
*/
|
|
3992
|
+
declare const walkerEmitter: Subject<WalkerContract>;
|
|
3993
|
+
/**
|
|
3994
|
+
* Walker complete emitter for strategy comparison completion.
|
|
3995
|
+
* Emits when all strategies have been tested and final results are available.
|
|
3996
|
+
*/
|
|
3997
|
+
declare const walkerCompleteSubject: Subject<IWalkerResults>;
|
|
3998
|
+
/**
|
|
3999
|
+
* Validation emitter for risk validation errors.
|
|
4000
|
+
* Emits when risk validation functions throw errors during signal checking.
|
|
4001
|
+
*/
|
|
4002
|
+
declare const validationSubject: Subject<Error>;
|
|
4003
|
+
|
|
4004
|
+
declare const emitters_doneBacktestSubject: typeof doneBacktestSubject;
|
|
4005
|
+
declare const emitters_doneLiveSubject: typeof doneLiveSubject;
|
|
4006
|
+
declare const emitters_doneWalkerSubject: typeof doneWalkerSubject;
|
|
4007
|
+
declare const emitters_errorEmitter: typeof errorEmitter;
|
|
4008
|
+
declare const emitters_performanceEmitter: typeof performanceEmitter;
|
|
4009
|
+
declare const emitters_progressEmitter: typeof progressEmitter;
|
|
4010
|
+
declare const emitters_signalBacktestEmitter: typeof signalBacktestEmitter;
|
|
4011
|
+
declare const emitters_signalEmitter: typeof signalEmitter;
|
|
4012
|
+
declare const emitters_signalLiveEmitter: typeof signalLiveEmitter;
|
|
4013
|
+
declare const emitters_validationSubject: typeof validationSubject;
|
|
4014
|
+
declare const emitters_walkerCompleteSubject: typeof walkerCompleteSubject;
|
|
4015
|
+
declare const emitters_walkerEmitter: typeof walkerEmitter;
|
|
4016
|
+
declare namespace emitters {
|
|
4017
|
+
export { emitters_doneBacktestSubject as doneBacktestSubject, emitters_doneLiveSubject as doneLiveSubject, emitters_doneWalkerSubject as doneWalkerSubject, emitters_errorEmitter as errorEmitter, emitters_performanceEmitter as performanceEmitter, emitters_progressEmitter as progressEmitter, emitters_signalBacktestEmitter as signalBacktestEmitter, emitters_signalEmitter as signalEmitter, emitters_signalLiveEmitter as signalLiveEmitter, emitters_validationSubject as validationSubject, emitters_walkerCompleteSubject as walkerCompleteSubject, emitters_walkerEmitter as walkerEmitter };
|
|
2406
4018
|
}
|
|
2407
4019
|
|
|
2408
4020
|
/**
|
|
@@ -2650,6 +4262,7 @@ declare class StrategyConnectionService implements IStrategy {
|
|
|
2650
4262
|
private readonly loggerService;
|
|
2651
4263
|
private readonly executionContextService;
|
|
2652
4264
|
private readonly strategySchemaService;
|
|
4265
|
+
private readonly riskConnectionService;
|
|
2653
4266
|
private readonly exchangeConnectionService;
|
|
2654
4267
|
private readonly methodContextService;
|
|
2655
4268
|
/**
|
|
@@ -2682,97 +4295,327 @@ declare class StrategyConnectionService implements IStrategy {
|
|
|
2682
4295
|
*/
|
|
2683
4296
|
backtest: (candles: ICandleData[]) => Promise<IStrategyBacktestResult>;
|
|
2684
4297
|
/**
|
|
2685
|
-
* Stops the specified strategy from generating new signals.
|
|
4298
|
+
* Stops the specified strategy from generating new signals.
|
|
4299
|
+
*
|
|
4300
|
+
* Delegates to ClientStrategy.stop() which sets internal flag to prevent
|
|
4301
|
+
* getSignal from being called on subsequent ticks.
|
|
4302
|
+
*
|
|
4303
|
+
* @param strategyName - Name of strategy to stop
|
|
4304
|
+
* @returns Promise that resolves when stop flag is set
|
|
4305
|
+
*/
|
|
4306
|
+
stop: (strategyName: StrategyName) => Promise<void>;
|
|
4307
|
+
/**
|
|
4308
|
+
* Clears the memoized ClientStrategy instance from cache.
|
|
4309
|
+
*
|
|
4310
|
+
* Forces re-initialization of strategy on next getStrategy call.
|
|
4311
|
+
* Useful for resetting strategy state or releasing resources.
|
|
4312
|
+
*
|
|
4313
|
+
* @param strategyName - Name of strategy to clear from cache
|
|
4314
|
+
*/
|
|
4315
|
+
clear: (strategyName: StrategyName) => Promise<void>;
|
|
4316
|
+
}
|
|
4317
|
+
|
|
4318
|
+
/**
|
|
4319
|
+
* Client implementation for backtest timeframe generation.
|
|
4320
|
+
*
|
|
4321
|
+
* Features:
|
|
4322
|
+
* - Generates timestamp arrays for backtest iteration
|
|
4323
|
+
* - Singleshot caching prevents redundant generation
|
|
4324
|
+
* - Configurable interval spacing (1m to 3d)
|
|
4325
|
+
* - Callback support for validation and logging
|
|
4326
|
+
*
|
|
4327
|
+
* Used by BacktestLogicPrivateService to iterate through historical periods.
|
|
4328
|
+
*/
|
|
4329
|
+
declare class ClientFrame implements IFrame {
|
|
4330
|
+
readonly params: IFrameParams;
|
|
4331
|
+
constructor(params: IFrameParams);
|
|
4332
|
+
/**
|
|
4333
|
+
* Generates timeframe array for backtest period.
|
|
4334
|
+
* Results are cached via singleshot pattern.
|
|
4335
|
+
*
|
|
4336
|
+
* @param symbol - Trading pair symbol (unused, for API consistency)
|
|
4337
|
+
* @returns Promise resolving to array of Date objects
|
|
4338
|
+
* @throws Error if interval is invalid
|
|
4339
|
+
*/
|
|
4340
|
+
getTimeframe: ((symbol: string) => Promise<Date[]>) & functools_kit.ISingleshotClearable;
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
/**
|
|
4344
|
+
* Connection service routing frame operations to correct ClientFrame instance.
|
|
4345
|
+
*
|
|
4346
|
+
* Routes all IFrame method calls to the appropriate frame implementation
|
|
4347
|
+
* based on methodContextService.context.frameName. Uses memoization to cache
|
|
4348
|
+
* ClientFrame instances for performance.
|
|
4349
|
+
*
|
|
4350
|
+
* Key features:
|
|
4351
|
+
* - Automatic frame routing via method context
|
|
4352
|
+
* - Memoized ClientFrame instances by frameName
|
|
4353
|
+
* - Implements IFrame interface
|
|
4354
|
+
* - Backtest timeframe management (startDate, endDate, interval)
|
|
4355
|
+
*
|
|
4356
|
+
* Note: frameName is empty string for live mode (no frame constraints).
|
|
4357
|
+
*
|
|
4358
|
+
* @example
|
|
4359
|
+
* ```typescript
|
|
4360
|
+
* // Used internally by framework
|
|
4361
|
+
* const timeframe = await frameConnectionService.getTimeframe("BTCUSDT");
|
|
4362
|
+
* // Automatically routes to correct frame based on methodContext
|
|
4363
|
+
* ```
|
|
4364
|
+
*/
|
|
4365
|
+
declare class FrameConnectionService implements IFrame {
|
|
4366
|
+
private readonly loggerService;
|
|
4367
|
+
private readonly frameSchemaService;
|
|
4368
|
+
private readonly methodContextService;
|
|
4369
|
+
/**
|
|
4370
|
+
* Retrieves memoized ClientFrame instance for given frame name.
|
|
4371
|
+
*
|
|
4372
|
+
* Creates ClientFrame on first call, returns cached instance on subsequent calls.
|
|
4373
|
+
* Cache key is frameName string.
|
|
4374
|
+
*
|
|
4375
|
+
* @param frameName - Name of registered frame schema
|
|
4376
|
+
* @returns Configured ClientFrame instance
|
|
4377
|
+
*/
|
|
4378
|
+
getFrame: ((frameName: FrameName) => ClientFrame) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, ClientFrame>;
|
|
4379
|
+
/**
|
|
4380
|
+
* Retrieves backtest timeframe boundaries for symbol.
|
|
4381
|
+
*
|
|
4382
|
+
* Returns startDate and endDate from frame configuration.
|
|
4383
|
+
* Used to limit backtest execution to specific date range.
|
|
4384
|
+
*
|
|
4385
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
4386
|
+
* @returns Promise resolving to { startDate: Date, endDate: Date }
|
|
4387
|
+
*/
|
|
4388
|
+
getTimeframe: (symbol: string) => Promise<Date[]>;
|
|
4389
|
+
}
|
|
4390
|
+
|
|
4391
|
+
/**
|
|
4392
|
+
* Client implementation for position sizing calculation.
|
|
4393
|
+
*
|
|
4394
|
+
* Features:
|
|
4395
|
+
* - Multiple sizing methods (fixed %, Kelly, ATR)
|
|
4396
|
+
* - Min/max position constraints
|
|
4397
|
+
* - Max position percentage limit
|
|
4398
|
+
* - Callback support for validation and logging
|
|
4399
|
+
*
|
|
4400
|
+
* Used by strategy execution to determine optimal position sizes.
|
|
4401
|
+
*/
|
|
4402
|
+
declare class ClientSizing implements ISizing {
|
|
4403
|
+
readonly params: ISizingParams;
|
|
4404
|
+
constructor(params: ISizingParams);
|
|
4405
|
+
/**
|
|
4406
|
+
* Calculates position size based on configured method and constraints.
|
|
4407
|
+
*
|
|
4408
|
+
* @param params - Calculation parameters (symbol, balance, prices, etc.)
|
|
4409
|
+
* @returns Promise resolving to calculated position size
|
|
4410
|
+
* @throws Error if required parameters are missing or invalid
|
|
4411
|
+
*/
|
|
4412
|
+
calculate(params: ISizingCalculateParams): Promise<number>;
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
/**
|
|
4416
|
+
* Connection service routing sizing operations to correct ClientSizing instance.
|
|
4417
|
+
*
|
|
4418
|
+
* Routes sizing method calls to the appropriate sizing implementation
|
|
4419
|
+
* based on the provided sizingName parameter. Uses memoization to cache
|
|
4420
|
+
* ClientSizing instances for performance.
|
|
4421
|
+
*
|
|
4422
|
+
* Key features:
|
|
4423
|
+
* - Explicit sizing routing via sizingName parameter
|
|
4424
|
+
* - Memoized ClientSizing instances by sizingName
|
|
4425
|
+
* - Position size calculation with risk management
|
|
4426
|
+
*
|
|
4427
|
+
* Note: sizingName is empty string for strategies without sizing configuration.
|
|
4428
|
+
*
|
|
4429
|
+
* @example
|
|
4430
|
+
* ```typescript
|
|
4431
|
+
* // Used internally by framework
|
|
4432
|
+
* const quantity = await sizingConnectionService.calculate(
|
|
4433
|
+
* {
|
|
4434
|
+
* symbol: "BTCUSDT",
|
|
4435
|
+
* accountBalance: 10000,
|
|
4436
|
+
* priceOpen: 50000,
|
|
4437
|
+
* priceStopLoss: 49000,
|
|
4438
|
+
* method: "fixed-percentage"
|
|
4439
|
+
* },
|
|
4440
|
+
* { sizingName: "conservative" }
|
|
4441
|
+
* );
|
|
4442
|
+
* ```
|
|
4443
|
+
*/
|
|
4444
|
+
declare class SizingConnectionService {
|
|
4445
|
+
private readonly loggerService;
|
|
4446
|
+
private readonly sizingSchemaService;
|
|
4447
|
+
/**
|
|
4448
|
+
* Retrieves memoized ClientSizing instance for given sizing name.
|
|
2686
4449
|
*
|
|
2687
|
-
*
|
|
2688
|
-
*
|
|
4450
|
+
* Creates ClientSizing on first call, returns cached instance on subsequent calls.
|
|
4451
|
+
* Cache key is sizingName string.
|
|
2689
4452
|
*
|
|
2690
|
-
* @param
|
|
2691
|
-
* @returns
|
|
4453
|
+
* @param sizingName - Name of registered sizing schema
|
|
4454
|
+
* @returns Configured ClientSizing instance
|
|
2692
4455
|
*/
|
|
2693
|
-
|
|
4456
|
+
getSizing: ((sizingName: SizingName) => ClientSizing) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, ClientSizing>;
|
|
2694
4457
|
/**
|
|
2695
|
-
*
|
|
4458
|
+
* Calculates position size based on risk parameters and configured method.
|
|
2696
4459
|
*
|
|
2697
|
-
*
|
|
2698
|
-
*
|
|
4460
|
+
* Routes to appropriate ClientSizing instance based on provided context.
|
|
4461
|
+
* Supports multiple sizing methods: fixed-percentage, kelly-criterion, atr-based.
|
|
2699
4462
|
*
|
|
2700
|
-
* @param
|
|
4463
|
+
* @param params - Calculation parameters (symbol, balance, prices, method-specific data)
|
|
4464
|
+
* @param context - Execution context with sizing name
|
|
4465
|
+
* @returns Promise resolving to calculated position size
|
|
2701
4466
|
*/
|
|
2702
|
-
|
|
4467
|
+
calculate: (params: ISizingCalculateParams, context: {
|
|
4468
|
+
sizingName: SizingName;
|
|
4469
|
+
}) => Promise<number>;
|
|
2703
4470
|
}
|
|
2704
4471
|
|
|
4472
|
+
/** Type for active position map */
|
|
4473
|
+
type RiskMap = Map<string, IRiskActivePosition>;
|
|
4474
|
+
/** Symbol indicating that positions need to be fetched from persistence */
|
|
4475
|
+
declare const POSITION_NEED_FETCH: unique symbol;
|
|
2705
4476
|
/**
|
|
2706
|
-
*
|
|
4477
|
+
* ClientRisk implementation for portfolio-level risk management.
|
|
2707
4478
|
*
|
|
2708
|
-
*
|
|
2709
|
-
* -
|
|
2710
|
-
* -
|
|
2711
|
-
* - Configurable interval spacing (1m to 3d)
|
|
2712
|
-
* - Callback support for validation and logging
|
|
4479
|
+
* Provides risk checking logic to prevent signals that violate configured limits:
|
|
4480
|
+
* - Maximum concurrent positions (tracks across all strategies)
|
|
4481
|
+
* - Custom validations with access to all active positions
|
|
2713
4482
|
*
|
|
2714
|
-
*
|
|
4483
|
+
* Multiple ClientStrategy instances share the same ClientRisk instance,
|
|
4484
|
+
* allowing cross-strategy risk analysis.
|
|
4485
|
+
*
|
|
4486
|
+
* Used internally by strategy execution to validate signals before opening positions.
|
|
2715
4487
|
*/
|
|
2716
|
-
declare class
|
|
2717
|
-
readonly params:
|
|
2718
|
-
constructor(params: IFrameParams);
|
|
4488
|
+
declare class ClientRisk implements IRisk {
|
|
4489
|
+
readonly params: IRiskParams;
|
|
2719
4490
|
/**
|
|
2720
|
-
*
|
|
2721
|
-
*
|
|
4491
|
+
* Map of active positions tracked across all strategies.
|
|
4492
|
+
* Key: `${strategyName}:${exchangeName}:${symbol}`
|
|
4493
|
+
* Starts as POSITION_NEED_FETCH symbol, gets initialized on first use.
|
|
4494
|
+
*/
|
|
4495
|
+
_activePositions: RiskMap | typeof POSITION_NEED_FETCH;
|
|
4496
|
+
constructor(params: IRiskParams);
|
|
4497
|
+
/**
|
|
4498
|
+
* Initializes active positions by loading from persistence.
|
|
4499
|
+
* Uses singleshot pattern to ensure initialization happens exactly once.
|
|
4500
|
+
* Skips persistence in backtest mode.
|
|
4501
|
+
*/
|
|
4502
|
+
private waitForInit;
|
|
4503
|
+
/**
|
|
4504
|
+
* Persists current active positions to disk.
|
|
4505
|
+
*/
|
|
4506
|
+
private _updatePositions;
|
|
4507
|
+
/**
|
|
4508
|
+
* Registers a new opened signal.
|
|
4509
|
+
* Called by StrategyConnectionService after signal is opened.
|
|
4510
|
+
*/
|
|
4511
|
+
addSignal(symbol: string, context: {
|
|
4512
|
+
strategyName: string;
|
|
4513
|
+
riskName: string;
|
|
4514
|
+
}): Promise<void>;
|
|
4515
|
+
/**
|
|
4516
|
+
* Removes a closed signal.
|
|
4517
|
+
* Called by StrategyConnectionService when signal is closed.
|
|
4518
|
+
*/
|
|
4519
|
+
removeSignal(symbol: string, context: {
|
|
4520
|
+
strategyName: string;
|
|
4521
|
+
riskName: string;
|
|
4522
|
+
}): Promise<void>;
|
|
4523
|
+
/**
|
|
4524
|
+
* Checks if a signal should be allowed based on risk limits.
|
|
2722
4525
|
*
|
|
2723
|
-
*
|
|
2724
|
-
*
|
|
2725
|
-
*
|
|
4526
|
+
* Executes custom validations with access to:
|
|
4527
|
+
* - Passthrough params from ClientStrategy (symbol, strategyName, exchangeName, currentPrice, timestamp)
|
|
4528
|
+
* - Active positions via this.activePositions getter
|
|
4529
|
+
*
|
|
4530
|
+
* Returns false immediately if any validation throws error.
|
|
4531
|
+
* Triggers callbacks (onRejected, onAllowed) based on result.
|
|
4532
|
+
*
|
|
4533
|
+
* @param params - Risk check arguments (passthrough from ClientStrategy)
|
|
4534
|
+
* @returns Promise resolving to true if allowed, false if rejected
|
|
2726
4535
|
*/
|
|
2727
|
-
|
|
4536
|
+
checkSignal: (params: IRiskCheckArgs) => Promise<boolean>;
|
|
2728
4537
|
}
|
|
2729
4538
|
|
|
2730
4539
|
/**
|
|
2731
|
-
* Connection service routing
|
|
4540
|
+
* Connection service routing risk operations to correct ClientRisk instance.
|
|
2732
4541
|
*
|
|
2733
|
-
* Routes
|
|
2734
|
-
* based on
|
|
2735
|
-
*
|
|
4542
|
+
* Routes risk checking calls to the appropriate risk implementation
|
|
4543
|
+
* based on the provided riskName parameter. Uses memoization to cache
|
|
4544
|
+
* ClientRisk instances for performance.
|
|
2736
4545
|
*
|
|
2737
4546
|
* Key features:
|
|
2738
|
-
* -
|
|
2739
|
-
* - Memoized
|
|
2740
|
-
* -
|
|
2741
|
-
* - Backtest timeframe management (startDate, endDate, interval)
|
|
4547
|
+
* - Explicit risk routing via riskName parameter
|
|
4548
|
+
* - Memoized ClientRisk instances by riskName
|
|
4549
|
+
* - Risk limit validation for signals
|
|
2742
4550
|
*
|
|
2743
|
-
* Note:
|
|
4551
|
+
* Note: riskName is empty string for strategies without risk configuration.
|
|
2744
4552
|
*
|
|
2745
4553
|
* @example
|
|
2746
4554
|
* ```typescript
|
|
2747
4555
|
* // Used internally by framework
|
|
2748
|
-
* const
|
|
2749
|
-
*
|
|
4556
|
+
* const result = await riskConnectionService.checkSignal(
|
|
4557
|
+
* {
|
|
4558
|
+
* symbol: "BTCUSDT",
|
|
4559
|
+
* positionSize: 0.5,
|
|
4560
|
+
* currentPrice: 50000,
|
|
4561
|
+
* portfolioBalance: 100000,
|
|
4562
|
+
* currentDrawdown: 5,
|
|
4563
|
+
* currentPositions: 3,
|
|
4564
|
+
* dailyPnl: -2,
|
|
4565
|
+
* currentSymbolExposure: 8
|
|
4566
|
+
* },
|
|
4567
|
+
* { riskName: "conservative" }
|
|
4568
|
+
* );
|
|
2750
4569
|
* ```
|
|
2751
4570
|
*/
|
|
2752
|
-
declare class
|
|
4571
|
+
declare class RiskConnectionService {
|
|
2753
4572
|
private readonly loggerService;
|
|
2754
|
-
private readonly
|
|
2755
|
-
private readonly methodContextService;
|
|
4573
|
+
private readonly riskSchemaService;
|
|
2756
4574
|
/**
|
|
2757
|
-
* Retrieves memoized
|
|
4575
|
+
* Retrieves memoized ClientRisk instance for given risk name.
|
|
2758
4576
|
*
|
|
2759
|
-
* Creates
|
|
2760
|
-
* Cache key is
|
|
4577
|
+
* Creates ClientRisk on first call, returns cached instance on subsequent calls.
|
|
4578
|
+
* Cache key is riskName string.
|
|
2761
4579
|
*
|
|
2762
|
-
* @param
|
|
2763
|
-
* @returns Configured
|
|
4580
|
+
* @param riskName - Name of registered risk schema
|
|
4581
|
+
* @returns Configured ClientRisk instance
|
|
2764
4582
|
*/
|
|
2765
|
-
|
|
4583
|
+
getRisk: ((riskName: RiskName) => ClientRisk) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, ClientRisk>;
|
|
2766
4584
|
/**
|
|
2767
|
-
*
|
|
4585
|
+
* Checks if a signal should be allowed based on risk limits.
|
|
2768
4586
|
*
|
|
2769
|
-
*
|
|
2770
|
-
*
|
|
4587
|
+
* Routes to appropriate ClientRisk instance based on provided context.
|
|
4588
|
+
* Validates portfolio drawdown, symbol exposure, position count, and daily loss limits.
|
|
2771
4589
|
*
|
|
2772
|
-
* @param
|
|
2773
|
-
* @
|
|
4590
|
+
* @param params - Risk check arguments (portfolio state, position details)
|
|
4591
|
+
* @param context - Execution context with risk name
|
|
4592
|
+
* @returns Promise resolving to risk check result
|
|
2774
4593
|
*/
|
|
2775
|
-
|
|
4594
|
+
checkSignal: (params: IRiskCheckArgs, context: {
|
|
4595
|
+
riskName: RiskName;
|
|
4596
|
+
}) => Promise<boolean>;
|
|
4597
|
+
/**
|
|
4598
|
+
* Registers an opened signal with the risk management system.
|
|
4599
|
+
* Routes to appropriate ClientRisk instance.
|
|
4600
|
+
*
|
|
4601
|
+
* @param symbol - Trading pair symbol
|
|
4602
|
+
* @param context - Context information (strategyName, riskName)
|
|
4603
|
+
*/
|
|
4604
|
+
addSignal: (symbol: string, context: {
|
|
4605
|
+
strategyName: string;
|
|
4606
|
+
riskName: RiskName;
|
|
4607
|
+
}) => Promise<void>;
|
|
4608
|
+
/**
|
|
4609
|
+
* Removes a closed signal from the risk management system.
|
|
4610
|
+
* Routes to appropriate ClientRisk instance.
|
|
4611
|
+
*
|
|
4612
|
+
* @param symbol - Trading pair symbol
|
|
4613
|
+
* @param context - Context information (strategyName, riskName)
|
|
4614
|
+
*/
|
|
4615
|
+
removeSignal: (symbol: string, context: {
|
|
4616
|
+
strategyName: string;
|
|
4617
|
+
riskName: RiskName;
|
|
4618
|
+
}) => Promise<void>;
|
|
2776
4619
|
}
|
|
2777
4620
|
|
|
2778
4621
|
/**
|
|
@@ -2914,6 +4757,90 @@ declare class FrameGlobalService {
|
|
|
2914
4757
|
getTimeframe: (symbol: string) => Promise<Date[]>;
|
|
2915
4758
|
}
|
|
2916
4759
|
|
|
4760
|
+
/**
|
|
4761
|
+
* Global service for sizing operations.
|
|
4762
|
+
*
|
|
4763
|
+
* Wraps SizingConnectionService for position size calculation.
|
|
4764
|
+
* Used internally by strategy execution and public API.
|
|
4765
|
+
*/
|
|
4766
|
+
declare class SizingGlobalService {
|
|
4767
|
+
private readonly loggerService;
|
|
4768
|
+
private readonly sizingConnectionService;
|
|
4769
|
+
/**
|
|
4770
|
+
* Calculates position size based on risk parameters.
|
|
4771
|
+
*
|
|
4772
|
+
* @param params - Calculation parameters (symbol, balance, prices, method-specific data)
|
|
4773
|
+
* @param context - Execution context with sizing name
|
|
4774
|
+
* @returns Promise resolving to calculated position size
|
|
4775
|
+
*/
|
|
4776
|
+
calculate: (params: ISizingCalculateParams, context: {
|
|
4777
|
+
sizingName: SizingName;
|
|
4778
|
+
}) => Promise<number>;
|
|
4779
|
+
}
|
|
4780
|
+
|
|
4781
|
+
/**
|
|
4782
|
+
* Global service for risk operations.
|
|
4783
|
+
*
|
|
4784
|
+
* Wraps RiskConnectionService for risk limit validation.
|
|
4785
|
+
* Used internally by strategy execution and public API.
|
|
4786
|
+
*/
|
|
4787
|
+
declare class RiskGlobalService {
|
|
4788
|
+
private readonly loggerService;
|
|
4789
|
+
private readonly riskConnectionService;
|
|
4790
|
+
/**
|
|
4791
|
+
* Checks if a signal should be allowed based on risk limits.
|
|
4792
|
+
*
|
|
4793
|
+
* @param params - Risk check arguments (portfolio state, position details)
|
|
4794
|
+
* @param context - Execution context with risk name
|
|
4795
|
+
* @returns Promise resolving to risk check result
|
|
4796
|
+
*/
|
|
4797
|
+
checkSignal: (params: IRiskCheckArgs, context: {
|
|
4798
|
+
riskName: RiskName;
|
|
4799
|
+
}) => Promise<boolean>;
|
|
4800
|
+
/**
|
|
4801
|
+
* Registers an opened signal with the risk management system.
|
|
4802
|
+
*
|
|
4803
|
+
* @param symbol - Trading pair symbol
|
|
4804
|
+
* @param context - Context information (strategyName, riskName)
|
|
4805
|
+
*/
|
|
4806
|
+
addSignal: (symbol: string, context: {
|
|
4807
|
+
strategyName: string;
|
|
4808
|
+
riskName: RiskName;
|
|
4809
|
+
}) => Promise<void>;
|
|
4810
|
+
/**
|
|
4811
|
+
* Removes a closed signal from the risk management system.
|
|
4812
|
+
*
|
|
4813
|
+
* @param symbol - Trading pair symbol
|
|
4814
|
+
* @param context - Context information (strategyName, riskName)
|
|
4815
|
+
*/
|
|
4816
|
+
removeSignal: (symbol: string, context: {
|
|
4817
|
+
strategyName: string;
|
|
4818
|
+
riskName: RiskName;
|
|
4819
|
+
}) => Promise<void>;
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
/**
|
|
4823
|
+
* Global service providing access to walker functionality.
|
|
4824
|
+
*
|
|
4825
|
+
* Simple wrapper around WalkerLogicPublicService for dependency injection.
|
|
4826
|
+
* Used by public API exports.
|
|
4827
|
+
*/
|
|
4828
|
+
declare class WalkerGlobalService {
|
|
4829
|
+
private readonly loggerService;
|
|
4830
|
+
private readonly walkerLogicPublicService;
|
|
4831
|
+
/**
|
|
4832
|
+
* Runs walker comparison for a symbol with context propagation.
|
|
4833
|
+
*
|
|
4834
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
4835
|
+
* @param context - Walker context with strategies and metric
|
|
4836
|
+
*/
|
|
4837
|
+
run: (symbol: string, context: {
|
|
4838
|
+
walkerName: string;
|
|
4839
|
+
exchangeName: string;
|
|
4840
|
+
frameName: string;
|
|
4841
|
+
}) => AsyncGenerator<WalkerContract, any, any>;
|
|
4842
|
+
}
|
|
4843
|
+
|
|
2917
4844
|
/**
|
|
2918
4845
|
* Service for managing exchange schema registry.
|
|
2919
4846
|
*
|
|
@@ -2954,109 +4881,252 @@ declare class ExchangeSchemaService {
|
|
|
2954
4881
|
*/
|
|
2955
4882
|
override: (key: ExchangeName, value: Partial<IExchangeSchema>) => IExchangeSchema;
|
|
2956
4883
|
/**
|
|
2957
|
-
* Retrieves an exchange schema by name.
|
|
4884
|
+
* Retrieves an exchange schema by name.
|
|
4885
|
+
*
|
|
4886
|
+
* @param key - Exchange name
|
|
4887
|
+
* @returns Exchange schema configuration
|
|
4888
|
+
* @throws Error if exchange name doesn't exist
|
|
4889
|
+
*/
|
|
4890
|
+
get: (key: ExchangeName) => IExchangeSchema;
|
|
4891
|
+
}
|
|
4892
|
+
|
|
4893
|
+
/**
|
|
4894
|
+
* Service for managing strategy schema registry.
|
|
4895
|
+
*
|
|
4896
|
+
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
4897
|
+
* Strategies are registered via addStrategy() and retrieved by name.
|
|
4898
|
+
*/
|
|
4899
|
+
declare class StrategySchemaService {
|
|
4900
|
+
readonly loggerService: LoggerService;
|
|
4901
|
+
private _registry;
|
|
4902
|
+
/**
|
|
4903
|
+
* Registers a new strategy schema.
|
|
4904
|
+
*
|
|
4905
|
+
* @param key - Unique strategy name
|
|
4906
|
+
* @param value - Strategy schema configuration
|
|
4907
|
+
* @throws Error if strategy name already exists
|
|
4908
|
+
*/
|
|
4909
|
+
register: (key: StrategyName, value: IStrategySchema) => void;
|
|
4910
|
+
/**
|
|
4911
|
+
* Validates strategy schema structure for required properties.
|
|
4912
|
+
*
|
|
4913
|
+
* Performs shallow validation to ensure all required properties exist
|
|
4914
|
+
* and have correct types before registration in the registry.
|
|
4915
|
+
*
|
|
4916
|
+
* @param strategySchema - Strategy schema to validate
|
|
4917
|
+
* @throws Error if strategyName is missing or not a string
|
|
4918
|
+
* @throws Error if interval is missing or not a valid SignalInterval
|
|
4919
|
+
* @throws Error if getSignal is missing or not a function
|
|
4920
|
+
*/
|
|
4921
|
+
private validateShallow;
|
|
4922
|
+
/**
|
|
4923
|
+
* Overrides an existing strategy schema with partial updates.
|
|
4924
|
+
*
|
|
4925
|
+
* @param key - Strategy name to override
|
|
4926
|
+
* @param value - Partial schema updates
|
|
4927
|
+
* @returns Updated strategy schema
|
|
4928
|
+
* @throws Error if strategy name doesn't exist
|
|
4929
|
+
*/
|
|
4930
|
+
override: (key: StrategyName, value: Partial<IStrategySchema>) => IStrategySchema;
|
|
4931
|
+
/**
|
|
4932
|
+
* Retrieves a strategy schema by name.
|
|
4933
|
+
*
|
|
4934
|
+
* @param key - Strategy name
|
|
4935
|
+
* @returns Strategy schema configuration
|
|
4936
|
+
* @throws Error if strategy name doesn't exist
|
|
4937
|
+
*/
|
|
4938
|
+
get: (key: StrategyName) => IStrategySchema;
|
|
4939
|
+
}
|
|
4940
|
+
|
|
4941
|
+
/**
|
|
4942
|
+
* Service for managing frame schema registry.
|
|
4943
|
+
*
|
|
4944
|
+
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
4945
|
+
* Frames are registered via addFrame() and retrieved by name.
|
|
4946
|
+
*/
|
|
4947
|
+
declare class FrameSchemaService {
|
|
4948
|
+
readonly loggerService: LoggerService;
|
|
4949
|
+
private _registry;
|
|
4950
|
+
/**
|
|
4951
|
+
* Registers a new frame schema.
|
|
4952
|
+
*
|
|
4953
|
+
* @param key - Unique frame name
|
|
4954
|
+
* @param value - Frame schema configuration
|
|
4955
|
+
* @throws Error if frame name already exists
|
|
4956
|
+
*/
|
|
4957
|
+
register(key: FrameName, value: IFrameSchema): void;
|
|
4958
|
+
/**
|
|
4959
|
+
* Validates frame schema structure for required properties.
|
|
4960
|
+
*
|
|
4961
|
+
* Performs shallow validation to ensure all required properties exist
|
|
4962
|
+
* and have correct types before registration in the registry.
|
|
4963
|
+
*
|
|
4964
|
+
* @param frameSchema - Frame schema to validate
|
|
4965
|
+
* @throws Error if frameName is missing or not a string
|
|
4966
|
+
* @throws Error if interval is missing or not a valid FrameInterval
|
|
4967
|
+
* @throws Error if startDate is missing or not a Date
|
|
4968
|
+
* @throws Error if endDate is missing or not a Date
|
|
4969
|
+
*/
|
|
4970
|
+
private validateShallow;
|
|
4971
|
+
/**
|
|
4972
|
+
* Overrides an existing frame schema with partial updates.
|
|
4973
|
+
*
|
|
4974
|
+
* @param key - Frame name to override
|
|
4975
|
+
* @param value - Partial schema updates
|
|
4976
|
+
* @throws Error if frame name doesn't exist
|
|
4977
|
+
*/
|
|
4978
|
+
override(key: FrameName, value: Partial<IFrameSchema>): IFrameSchema;
|
|
4979
|
+
/**
|
|
4980
|
+
* Retrieves a frame schema by name.
|
|
4981
|
+
*
|
|
4982
|
+
* @param key - Frame name
|
|
4983
|
+
* @returns Frame schema configuration
|
|
4984
|
+
* @throws Error if frame name doesn't exist
|
|
4985
|
+
*/
|
|
4986
|
+
get(key: FrameName): IFrameSchema;
|
|
4987
|
+
}
|
|
4988
|
+
|
|
4989
|
+
/**
|
|
4990
|
+
* Service for managing sizing schema registry.
|
|
4991
|
+
*
|
|
4992
|
+
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
4993
|
+
* Sizing schemas are registered via addSizing() and retrieved by name.
|
|
4994
|
+
*/
|
|
4995
|
+
declare class SizingSchemaService {
|
|
4996
|
+
readonly loggerService: LoggerService;
|
|
4997
|
+
private _registry;
|
|
4998
|
+
/**
|
|
4999
|
+
* Registers a new sizing schema.
|
|
5000
|
+
*
|
|
5001
|
+
* @param key - Unique sizing name
|
|
5002
|
+
* @param value - Sizing schema configuration
|
|
5003
|
+
* @throws Error if sizing name already exists
|
|
5004
|
+
*/
|
|
5005
|
+
register(key: SizingName, value: ISizingSchema): void;
|
|
5006
|
+
/**
|
|
5007
|
+
* Validates sizing schema structure for required properties.
|
|
5008
|
+
*
|
|
5009
|
+
* Performs shallow validation to ensure all required properties exist
|
|
5010
|
+
* and have correct types before registration in the registry.
|
|
5011
|
+
*
|
|
5012
|
+
* @param sizingSchema - Sizing schema to validate
|
|
5013
|
+
* @throws Error if sizingName is missing or not a string
|
|
5014
|
+
* @throws Error if method is missing or not a valid sizing method
|
|
5015
|
+
* @throws Error if required method-specific fields are missing
|
|
5016
|
+
*/
|
|
5017
|
+
private validateShallow;
|
|
5018
|
+
/**
|
|
5019
|
+
* Overrides an existing sizing schema with partial updates.
|
|
5020
|
+
*
|
|
5021
|
+
* @param key - Sizing name to override
|
|
5022
|
+
* @param value - Partial schema updates
|
|
5023
|
+
* @throws Error if sizing name doesn't exist
|
|
5024
|
+
*/
|
|
5025
|
+
override(key: SizingName, value: Partial<ISizingSchema>): ISizingSchema;
|
|
5026
|
+
/**
|
|
5027
|
+
* Retrieves a sizing schema by name.
|
|
2958
5028
|
*
|
|
2959
|
-
* @param key -
|
|
2960
|
-
* @returns
|
|
2961
|
-
* @throws Error if
|
|
5029
|
+
* @param key - Sizing name
|
|
5030
|
+
* @returns Sizing schema configuration
|
|
5031
|
+
* @throws Error if sizing name doesn't exist
|
|
2962
5032
|
*/
|
|
2963
|
-
get
|
|
5033
|
+
get(key: SizingName): ISizingSchema;
|
|
2964
5034
|
}
|
|
2965
5035
|
|
|
2966
5036
|
/**
|
|
2967
|
-
* Service for managing
|
|
5037
|
+
* Service for managing risk schema registry.
|
|
2968
5038
|
*
|
|
2969
5039
|
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
2970
|
-
*
|
|
5040
|
+
* Risk profiles are registered via addRisk() and retrieved by name.
|
|
2971
5041
|
*/
|
|
2972
|
-
declare class
|
|
5042
|
+
declare class RiskSchemaService {
|
|
2973
5043
|
readonly loggerService: LoggerService;
|
|
2974
5044
|
private _registry;
|
|
2975
5045
|
/**
|
|
2976
|
-
* Registers a new
|
|
5046
|
+
* Registers a new risk schema.
|
|
2977
5047
|
*
|
|
2978
|
-
* @param key - Unique
|
|
2979
|
-
* @param value -
|
|
2980
|
-
* @throws Error if
|
|
5048
|
+
* @param key - Unique risk profile name
|
|
5049
|
+
* @param value - Risk schema configuration
|
|
5050
|
+
* @throws Error if risk name already exists
|
|
2981
5051
|
*/
|
|
2982
|
-
register: (key:
|
|
5052
|
+
register: (key: RiskName, value: IRiskSchema) => void;
|
|
2983
5053
|
/**
|
|
2984
|
-
* Validates
|
|
5054
|
+
* Validates risk schema structure for required properties.
|
|
2985
5055
|
*
|
|
2986
5056
|
* Performs shallow validation to ensure all required properties exist
|
|
2987
5057
|
* and have correct types before registration in the registry.
|
|
2988
5058
|
*
|
|
2989
|
-
* @param
|
|
2990
|
-
* @throws Error if
|
|
2991
|
-
* @throws Error if interval is missing or not a valid SignalInterval
|
|
2992
|
-
* @throws Error if getSignal is missing or not a function
|
|
5059
|
+
* @param riskSchema - Risk schema to validate
|
|
5060
|
+
* @throws Error if riskName is missing or not a string
|
|
2993
5061
|
*/
|
|
2994
5062
|
private validateShallow;
|
|
2995
5063
|
/**
|
|
2996
|
-
* Overrides an existing
|
|
5064
|
+
* Overrides an existing risk schema with partial updates.
|
|
2997
5065
|
*
|
|
2998
|
-
* @param key -
|
|
5066
|
+
* @param key - Risk name to override
|
|
2999
5067
|
* @param value - Partial schema updates
|
|
3000
|
-
* @returns Updated
|
|
3001
|
-
* @throws Error if
|
|
5068
|
+
* @returns Updated risk schema
|
|
5069
|
+
* @throws Error if risk name doesn't exist
|
|
3002
5070
|
*/
|
|
3003
|
-
override: (key:
|
|
5071
|
+
override: (key: RiskName, value: Partial<IRiskSchema>) => IRiskSchema;
|
|
3004
5072
|
/**
|
|
3005
|
-
* Retrieves a
|
|
5073
|
+
* Retrieves a risk schema by name.
|
|
3006
5074
|
*
|
|
3007
|
-
* @param key -
|
|
3008
|
-
* @returns
|
|
3009
|
-
* @throws Error if
|
|
5075
|
+
* @param key - Risk name
|
|
5076
|
+
* @returns Risk schema configuration
|
|
5077
|
+
* @throws Error if risk name doesn't exist
|
|
3010
5078
|
*/
|
|
3011
|
-
get: (key:
|
|
5079
|
+
get: (key: RiskName) => IRiskSchema;
|
|
3012
5080
|
}
|
|
3013
5081
|
|
|
3014
5082
|
/**
|
|
3015
|
-
* Service for managing
|
|
5083
|
+
* Service for managing walker schema registry.
|
|
3016
5084
|
*
|
|
3017
5085
|
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
3018
|
-
*
|
|
5086
|
+
* Walkers are registered via addWalker() and retrieved by name.
|
|
3019
5087
|
*/
|
|
3020
|
-
declare class
|
|
5088
|
+
declare class WalkerSchemaService {
|
|
3021
5089
|
readonly loggerService: LoggerService;
|
|
3022
5090
|
private _registry;
|
|
3023
5091
|
/**
|
|
3024
|
-
* Registers a new
|
|
5092
|
+
* Registers a new walker schema.
|
|
3025
5093
|
*
|
|
3026
|
-
* @param key - Unique
|
|
3027
|
-
* @param value -
|
|
3028
|
-
* @throws Error if
|
|
5094
|
+
* @param key - Unique walker name
|
|
5095
|
+
* @param value - Walker schema configuration
|
|
5096
|
+
* @throws Error if walker name already exists
|
|
3029
5097
|
*/
|
|
3030
|
-
register(key:
|
|
5098
|
+
register: (key: WalkerName, value: IWalkerSchema) => void;
|
|
3031
5099
|
/**
|
|
3032
|
-
* Validates
|
|
5100
|
+
* Validates walker schema structure for required properties.
|
|
3033
5101
|
*
|
|
3034
5102
|
* Performs shallow validation to ensure all required properties exist
|
|
3035
5103
|
* and have correct types before registration in the registry.
|
|
3036
5104
|
*
|
|
3037
|
-
* @param
|
|
5105
|
+
* @param walkerSchema - Walker schema to validate
|
|
5106
|
+
* @throws Error if walkerName is missing or not a string
|
|
5107
|
+
* @throws Error if exchangeName is missing or not a string
|
|
3038
5108
|
* @throws Error if frameName is missing or not a string
|
|
3039
|
-
* @throws Error if
|
|
3040
|
-
* @throws Error if
|
|
3041
|
-
* @throws Error if endDate is missing or not a Date
|
|
5109
|
+
* @throws Error if strategies is missing or not an array
|
|
5110
|
+
* @throws Error if strategies array is empty
|
|
3042
5111
|
*/
|
|
3043
5112
|
private validateShallow;
|
|
3044
5113
|
/**
|
|
3045
|
-
* Overrides an existing
|
|
5114
|
+
* Overrides an existing walker schema with partial updates.
|
|
3046
5115
|
*
|
|
3047
|
-
* @param key -
|
|
5116
|
+
* @param key - Walker name to override
|
|
3048
5117
|
* @param value - Partial schema updates
|
|
3049
|
-
* @
|
|
5118
|
+
* @returns Updated walker schema
|
|
5119
|
+
* @throws Error if walker name doesn't exist
|
|
3050
5120
|
*/
|
|
3051
|
-
override(key:
|
|
5121
|
+
override: (key: WalkerName, value: Partial<IWalkerSchema>) => IWalkerSchema;
|
|
3052
5122
|
/**
|
|
3053
|
-
* Retrieves a
|
|
5123
|
+
* Retrieves a walker schema by name.
|
|
3054
5124
|
*
|
|
3055
|
-
* @param key -
|
|
3056
|
-
* @returns
|
|
3057
|
-
* @throws Error if
|
|
5125
|
+
* @param key - Walker name
|
|
5126
|
+
* @returns Walker schema configuration
|
|
5127
|
+
* @throws Error if walker name doesn't exist
|
|
3058
5128
|
*/
|
|
3059
|
-
get(key:
|
|
5129
|
+
get: (key: WalkerName) => IWalkerSchema;
|
|
3060
5130
|
}
|
|
3061
5131
|
|
|
3062
5132
|
/**
|
|
@@ -3140,6 +5210,56 @@ declare class LiveLogicPrivateService {
|
|
|
3140
5210
|
run(symbol: string): AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed, void, unknown>;
|
|
3141
5211
|
}
|
|
3142
5212
|
|
|
5213
|
+
/**
|
|
5214
|
+
* Private service for walker orchestration (strategy comparison).
|
|
5215
|
+
*
|
|
5216
|
+
* Flow:
|
|
5217
|
+
* 1. Yields progress updates as each strategy completes
|
|
5218
|
+
* 2. Tracks best metric in real-time
|
|
5219
|
+
* 3. Returns final results with all strategies ranked
|
|
5220
|
+
*
|
|
5221
|
+
* Uses BacktestLogicPublicService internally for each strategy.
|
|
5222
|
+
*/
|
|
5223
|
+
declare class WalkerLogicPrivateService {
|
|
5224
|
+
private readonly loggerService;
|
|
5225
|
+
private readonly backtestLogicPublicService;
|
|
5226
|
+
private readonly backtestMarkdownService;
|
|
5227
|
+
private readonly walkerSchemaService;
|
|
5228
|
+
/**
|
|
5229
|
+
* Runs walker comparison for a symbol.
|
|
5230
|
+
*
|
|
5231
|
+
* Executes backtest for each strategy sequentially.
|
|
5232
|
+
* Yields WalkerContract after each strategy completes.
|
|
5233
|
+
*
|
|
5234
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
5235
|
+
* @param strategies - List of strategy names to compare
|
|
5236
|
+
* @param metric - Metric to use for comparison
|
|
5237
|
+
* @param context - Walker context with exchangeName, frameName, walkerName
|
|
5238
|
+
* @yields WalkerContract with progress after each strategy
|
|
5239
|
+
*
|
|
5240
|
+
* @example
|
|
5241
|
+
* ```typescript
|
|
5242
|
+
* for await (const progress of walkerLogic.run(
|
|
5243
|
+
* "BTCUSDT",
|
|
5244
|
+
* ["strategy-v1", "strategy-v2"],
|
|
5245
|
+
* "sharpeRatio",
|
|
5246
|
+
* {
|
|
5247
|
+
* exchangeName: "binance",
|
|
5248
|
+
* frameName: "1d-backtest",
|
|
5249
|
+
* walkerName: "my-optimizer"
|
|
5250
|
+
* }
|
|
5251
|
+
* )) {
|
|
5252
|
+
* console.log("Progress:", progress.strategiesTested, "/", progress.totalStrategies);
|
|
5253
|
+
* }
|
|
5254
|
+
* ```
|
|
5255
|
+
*/
|
|
5256
|
+
run(symbol: string, strategies: StrategyName[], metric: WalkerMetric, context: {
|
|
5257
|
+
exchangeName: string;
|
|
5258
|
+
frameName: string;
|
|
5259
|
+
walkerName: string;
|
|
5260
|
+
}): AsyncGenerator<WalkerContract>;
|
|
5261
|
+
}
|
|
5262
|
+
|
|
3143
5263
|
/**
|
|
3144
5264
|
* Public service for backtest orchestration with context management.
|
|
3145
5265
|
*
|
|
@@ -3235,6 +5355,46 @@ declare class LiveLogicPublicService {
|
|
|
3235
5355
|
}) => AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed, void, unknown>;
|
|
3236
5356
|
}
|
|
3237
5357
|
|
|
5358
|
+
/**
|
|
5359
|
+
* Public service for walker orchestration with context management.
|
|
5360
|
+
*
|
|
5361
|
+
* Wraps WalkerLogicPrivateService with MethodContextService to provide
|
|
5362
|
+
* implicit context propagation for strategyName, exchangeName, frameName, and walkerName.
|
|
5363
|
+
*
|
|
5364
|
+
* @example
|
|
5365
|
+
* ```typescript
|
|
5366
|
+
* const walkerLogicPublicService = inject(TYPES.walkerLogicPublicService);
|
|
5367
|
+
*
|
|
5368
|
+
* const results = await walkerLogicPublicService.run("BTCUSDT", {
|
|
5369
|
+
* walkerName: "my-optimizer",
|
|
5370
|
+
* exchangeName: "binance",
|
|
5371
|
+
* frameName: "1d-backtest",
|
|
5372
|
+
* strategies: ["strategy-v1", "strategy-v2"],
|
|
5373
|
+
* metric: "sharpeRatio",
|
|
5374
|
+
* });
|
|
5375
|
+
*
|
|
5376
|
+
* console.log("Best strategy:", results.bestStrategy);
|
|
5377
|
+
* ```
|
|
5378
|
+
*/
|
|
5379
|
+
declare class WalkerLogicPublicService {
|
|
5380
|
+
private readonly loggerService;
|
|
5381
|
+
private readonly walkerLogicPrivateService;
|
|
5382
|
+
private readonly walkerSchemaService;
|
|
5383
|
+
/**
|
|
5384
|
+
* Runs walker comparison for a symbol with context propagation.
|
|
5385
|
+
*
|
|
5386
|
+
* Executes backtests for all strategies.
|
|
5387
|
+
*
|
|
5388
|
+
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
5389
|
+
* @param context - Walker context with strategies and metric
|
|
5390
|
+
*/
|
|
5391
|
+
run: (symbol: string, context: {
|
|
5392
|
+
walkerName: string;
|
|
5393
|
+
exchangeName: string;
|
|
5394
|
+
frameName: string;
|
|
5395
|
+
}) => AsyncGenerator<WalkerContract, any, any>;
|
|
5396
|
+
}
|
|
5397
|
+
|
|
3238
5398
|
/**
|
|
3239
5399
|
* Global service providing access to live trading functionality.
|
|
3240
5400
|
*
|
|
@@ -3287,6 +5447,147 @@ declare class BacktestGlobalService {
|
|
|
3287
5447
|
}) => AsyncGenerator<IStrategyTickResultClosed, void, unknown>;
|
|
3288
5448
|
}
|
|
3289
5449
|
|
|
5450
|
+
/**
|
|
5451
|
+
* Portfolio Heatmap Markdown Service.
|
|
5452
|
+
*
|
|
5453
|
+
* Subscribes to signalEmitter and aggregates statistics across all symbols per strategy.
|
|
5454
|
+
* Provides portfolio-wide metrics and per-symbol breakdowns.
|
|
5455
|
+
*
|
|
5456
|
+
* Features:
|
|
5457
|
+
* - Real-time aggregation of closed signals
|
|
5458
|
+
* - Per-symbol statistics (Total PNL, Sharpe Ratio, Max Drawdown, Trades)
|
|
5459
|
+
* - Portfolio-wide aggregated metrics per strategy
|
|
5460
|
+
* - Markdown table report generation
|
|
5461
|
+
* - Safe math (handles NaN/Infinity gracefully)
|
|
5462
|
+
* - Strategy-based navigation using memoized storage
|
|
5463
|
+
*
|
|
5464
|
+
* @example
|
|
5465
|
+
* ```typescript
|
|
5466
|
+
* const service = new HeatMarkdownService();
|
|
5467
|
+
*
|
|
5468
|
+
* // Service automatically tracks all closed signals per strategy
|
|
5469
|
+
* const stats = await service.getData("my-strategy");
|
|
5470
|
+
* console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
|
|
5471
|
+
*
|
|
5472
|
+
* // Generate and save report
|
|
5473
|
+
* await service.dump("my-strategy", "./reports");
|
|
5474
|
+
* ```
|
|
5475
|
+
*/
|
|
5476
|
+
declare class HeatMarkdownService {
|
|
5477
|
+
/** Logger service for debug output */
|
|
5478
|
+
private readonly loggerService;
|
|
5479
|
+
/**
|
|
5480
|
+
* Memoized function to get or create HeatmapStorage for a strategy.
|
|
5481
|
+
* Each strategy gets its own isolated heatmap storage instance.
|
|
5482
|
+
*/
|
|
5483
|
+
private getStorage;
|
|
5484
|
+
/**
|
|
5485
|
+
* Processes tick events and accumulates closed signals.
|
|
5486
|
+
* Should be called from signal emitter subscription.
|
|
5487
|
+
*
|
|
5488
|
+
* Only processes closed signals - opened signals are ignored.
|
|
5489
|
+
*
|
|
5490
|
+
* @param data - Tick result from strategy execution (closed signals only)
|
|
5491
|
+
*/
|
|
5492
|
+
private tick;
|
|
5493
|
+
/**
|
|
5494
|
+
* Gets aggregated portfolio heatmap statistics for a strategy.
|
|
5495
|
+
*
|
|
5496
|
+
* @param strategyName - Strategy name to get heatmap data for
|
|
5497
|
+
* @returns Promise resolving to heatmap statistics with per-symbol and portfolio-wide metrics
|
|
5498
|
+
*
|
|
5499
|
+
* @example
|
|
5500
|
+
* ```typescript
|
|
5501
|
+
* const service = new HeatMarkdownService();
|
|
5502
|
+
* const stats = await service.getData("my-strategy");
|
|
5503
|
+
*
|
|
5504
|
+
* console.log(`Total symbols: ${stats.totalSymbols}`);
|
|
5505
|
+
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
5506
|
+
*
|
|
5507
|
+
* stats.symbols.forEach(row => {
|
|
5508
|
+
* console.log(`${row.symbol}: ${row.totalPnl}% (${row.totalTrades} trades)`);
|
|
5509
|
+
* });
|
|
5510
|
+
* ```
|
|
5511
|
+
*/
|
|
5512
|
+
getData: (strategyName: StrategyName) => Promise<IHeatmapStatistics>;
|
|
5513
|
+
/**
|
|
5514
|
+
* Generates markdown report with portfolio heatmap table for a strategy.
|
|
5515
|
+
*
|
|
5516
|
+
* @param strategyName - Strategy name to generate heatmap report for
|
|
5517
|
+
* @returns Promise resolving to markdown formatted report string
|
|
5518
|
+
*
|
|
5519
|
+
* @example
|
|
5520
|
+
* ```typescript
|
|
5521
|
+
* const service = new HeatMarkdownService();
|
|
5522
|
+
* const markdown = await service.getReport("my-strategy");
|
|
5523
|
+
* console.log(markdown);
|
|
5524
|
+
* // Output:
|
|
5525
|
+
* // # Portfolio Heatmap: my-strategy
|
|
5526
|
+
* //
|
|
5527
|
+
* // **Total Symbols:** 5 | **Portfolio PNL:** +45.3% | **Portfolio Sharpe:** 1.85 | **Total Trades:** 120
|
|
5528
|
+
* //
|
|
5529
|
+
* // | Symbol | Total PNL | Sharpe | Max DD | Trades |
|
|
5530
|
+
* // |--------|-----------|--------|--------|--------|
|
|
5531
|
+
* // | BTCUSDT | +15.5% | 2.10 | -2.5% | 45 |
|
|
5532
|
+
* // | ETHUSDT | +12.3% | 1.85 | -3.1% | 38 |
|
|
5533
|
+
* // ...
|
|
5534
|
+
* ```
|
|
5535
|
+
*/
|
|
5536
|
+
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
5537
|
+
/**
|
|
5538
|
+
* Saves heatmap report to disk for a strategy.
|
|
5539
|
+
*
|
|
5540
|
+
* Creates directory if it doesn't exist.
|
|
5541
|
+
* Default filename: {strategyName}.md
|
|
5542
|
+
*
|
|
5543
|
+
* @param strategyName - Strategy name to save heatmap report for
|
|
5544
|
+
* @param path - Optional directory path to save report (default: "./logs/heatmap")
|
|
5545
|
+
*
|
|
5546
|
+
* @example
|
|
5547
|
+
* ```typescript
|
|
5548
|
+
* const service = new HeatMarkdownService();
|
|
5549
|
+
*
|
|
5550
|
+
* // Save to default path: ./logs/heatmap/my-strategy.md
|
|
5551
|
+
* await service.dump("my-strategy");
|
|
5552
|
+
*
|
|
5553
|
+
* // Save to custom path: ./reports/my-strategy.md
|
|
5554
|
+
* await service.dump("my-strategy", "./reports");
|
|
5555
|
+
* ```
|
|
5556
|
+
*/
|
|
5557
|
+
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
5558
|
+
/**
|
|
5559
|
+
* Clears accumulated heatmap data from storage.
|
|
5560
|
+
* If strategyName is provided, clears only that strategy's data.
|
|
5561
|
+
* If strategyName is omitted, clears all strategies' data.
|
|
5562
|
+
*
|
|
5563
|
+
* @param strategyName - Optional strategy name to clear specific strategy data
|
|
5564
|
+
*
|
|
5565
|
+
* @example
|
|
5566
|
+
* ```typescript
|
|
5567
|
+
* const service = new HeatMarkdownService();
|
|
5568
|
+
*
|
|
5569
|
+
* // Clear specific strategy data
|
|
5570
|
+
* await service.clear("my-strategy");
|
|
5571
|
+
*
|
|
5572
|
+
* // Clear all strategies' data
|
|
5573
|
+
* await service.clear();
|
|
5574
|
+
* ```
|
|
5575
|
+
*/
|
|
5576
|
+
clear: (strategyName?: StrategyName) => Promise<void>;
|
|
5577
|
+
/**
|
|
5578
|
+
* Initializes the service by subscribing to signal events.
|
|
5579
|
+
* Uses singleshot to ensure initialization happens only once.
|
|
5580
|
+
* Automatically called on first use.
|
|
5581
|
+
*
|
|
5582
|
+
* @example
|
|
5583
|
+
* ```typescript
|
|
5584
|
+
* const service = new HeatMarkdownService();
|
|
5585
|
+
* await service.init(); // Subscribe to signal events
|
|
5586
|
+
* ```
|
|
5587
|
+
*/
|
|
5588
|
+
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
5589
|
+
}
|
|
5590
|
+
|
|
3290
5591
|
/**
|
|
3291
5592
|
* @class ExchangeValidationService
|
|
3292
5593
|
* Service for managing and validating exchange configurations
|
|
@@ -3335,6 +5636,12 @@ declare class StrategyValidationService {
|
|
|
3335
5636
|
* Injected logger service instance
|
|
3336
5637
|
*/
|
|
3337
5638
|
private readonly loggerService;
|
|
5639
|
+
/**
|
|
5640
|
+
* @private
|
|
5641
|
+
* @readonly
|
|
5642
|
+
* Injected risk validation service instance
|
|
5643
|
+
*/
|
|
5644
|
+
private readonly riskValidationService;
|
|
3338
5645
|
/**
|
|
3339
5646
|
* @private
|
|
3340
5647
|
* Map storing strategy schemas by strategy name
|
|
@@ -3347,9 +5654,10 @@ declare class StrategyValidationService {
|
|
|
3347
5654
|
*/
|
|
3348
5655
|
addStrategy: (strategyName: StrategyName, strategySchema: IStrategySchema) => void;
|
|
3349
5656
|
/**
|
|
3350
|
-
* Validates the existence of a strategy
|
|
5657
|
+
* Validates the existence of a strategy and its risk profile (if configured)
|
|
3351
5658
|
* @public
|
|
3352
5659
|
* @throws {Error} If strategyName is not found
|
|
5660
|
+
* @throws {Error} If riskName is configured but not found
|
|
3353
5661
|
* Memoized function to cache validation results
|
|
3354
5662
|
*/
|
|
3355
5663
|
validate: (strategyName: StrategyName, source: string) => void;
|
|
@@ -3398,28 +5706,155 @@ declare class FrameValidationService {
|
|
|
3398
5706
|
list: () => Promise<IFrameSchema[]>;
|
|
3399
5707
|
}
|
|
3400
5708
|
|
|
5709
|
+
/**
|
|
5710
|
+
* @class WalkerValidationService
|
|
5711
|
+
* Service for managing and validating walker configurations
|
|
5712
|
+
*/
|
|
5713
|
+
declare class WalkerValidationService {
|
|
5714
|
+
/**
|
|
5715
|
+
* @private
|
|
5716
|
+
* @readonly
|
|
5717
|
+
* Injected logger service instance
|
|
5718
|
+
*/
|
|
5719
|
+
private readonly loggerService;
|
|
5720
|
+
/**
|
|
5721
|
+
* @private
|
|
5722
|
+
* Map storing walker schemas by walker name
|
|
5723
|
+
*/
|
|
5724
|
+
private _walkerMap;
|
|
5725
|
+
/**
|
|
5726
|
+
* Adds a walker schema to the validation service
|
|
5727
|
+
* @public
|
|
5728
|
+
* @throws {Error} If walkerName already exists
|
|
5729
|
+
*/
|
|
5730
|
+
addWalker: (walkerName: WalkerName, walkerSchema: IWalkerSchema) => void;
|
|
5731
|
+
/**
|
|
5732
|
+
* Validates the existence of a walker
|
|
5733
|
+
* @public
|
|
5734
|
+
* @throws {Error} If walkerName is not found
|
|
5735
|
+
* Memoized function to cache validation results
|
|
5736
|
+
*/
|
|
5737
|
+
validate: (walkerName: WalkerName, source: string) => void;
|
|
5738
|
+
/**
|
|
5739
|
+
* Returns a list of all registered walker schemas
|
|
5740
|
+
* @public
|
|
5741
|
+
* @returns Array of walker schemas with their configurations
|
|
5742
|
+
*/
|
|
5743
|
+
list: () => Promise<IWalkerSchema[]>;
|
|
5744
|
+
}
|
|
5745
|
+
|
|
5746
|
+
/**
|
|
5747
|
+
* @class SizingValidationService
|
|
5748
|
+
* Service for managing and validating sizing configurations
|
|
5749
|
+
*/
|
|
5750
|
+
declare class SizingValidationService {
|
|
5751
|
+
/**
|
|
5752
|
+
* @private
|
|
5753
|
+
* @readonly
|
|
5754
|
+
* Injected logger service instance
|
|
5755
|
+
*/
|
|
5756
|
+
private readonly loggerService;
|
|
5757
|
+
/**
|
|
5758
|
+
* @private
|
|
5759
|
+
* Map storing sizing schemas by sizing name
|
|
5760
|
+
*/
|
|
5761
|
+
private _sizingMap;
|
|
5762
|
+
/**
|
|
5763
|
+
* Adds a sizing schema to the validation service
|
|
5764
|
+
* @public
|
|
5765
|
+
* @throws {Error} If sizingName already exists
|
|
5766
|
+
*/
|
|
5767
|
+
addSizing: (sizingName: SizingName, sizingSchema: ISizingSchema) => void;
|
|
5768
|
+
/**
|
|
5769
|
+
* Validates the existence of a sizing and optionally its method
|
|
5770
|
+
* @public
|
|
5771
|
+
* @throws {Error} If sizingName is not found
|
|
5772
|
+
* @throws {Error} If method is provided and doesn't match sizing schema method
|
|
5773
|
+
* Memoized function to cache validation results
|
|
5774
|
+
*/
|
|
5775
|
+
validate: (sizingName: SizingName, source: string, method?: "fixed-percentage" | "kelly-criterion" | "atr-based") => void;
|
|
5776
|
+
/**
|
|
5777
|
+
* Returns a list of all registered sizing schemas
|
|
5778
|
+
* @public
|
|
5779
|
+
* @returns Array of sizing schemas with their configurations
|
|
5780
|
+
*/
|
|
5781
|
+
list: () => Promise<ISizingSchema[]>;
|
|
5782
|
+
}
|
|
5783
|
+
|
|
5784
|
+
/**
|
|
5785
|
+
* @class RiskValidationService
|
|
5786
|
+
* Service for managing and validating risk configurations
|
|
5787
|
+
*/
|
|
5788
|
+
declare class RiskValidationService {
|
|
5789
|
+
/**
|
|
5790
|
+
* @private
|
|
5791
|
+
* @readonly
|
|
5792
|
+
* Injected logger service instance
|
|
5793
|
+
*/
|
|
5794
|
+
private readonly loggerService;
|
|
5795
|
+
/**
|
|
5796
|
+
* @private
|
|
5797
|
+
* Map storing risk schemas by risk name
|
|
5798
|
+
*/
|
|
5799
|
+
private _riskMap;
|
|
5800
|
+
/**
|
|
5801
|
+
* Adds a risk schema to the validation service
|
|
5802
|
+
* @public
|
|
5803
|
+
* @throws {Error} If riskName already exists
|
|
5804
|
+
*/
|
|
5805
|
+
addRisk: (riskName: RiskName, riskSchema: IRiskSchema) => void;
|
|
5806
|
+
/**
|
|
5807
|
+
* Validates the existence of a risk profile
|
|
5808
|
+
* @public
|
|
5809
|
+
* @throws {Error} If riskName is not found
|
|
5810
|
+
* Memoized function to cache validation results
|
|
5811
|
+
*/
|
|
5812
|
+
validate: (riskName: RiskName, source: string) => void;
|
|
5813
|
+
/**
|
|
5814
|
+
* Returns a list of all registered risk schemas
|
|
5815
|
+
* @public
|
|
5816
|
+
* @returns Array of risk schemas with their configurations
|
|
5817
|
+
*/
|
|
5818
|
+
list: () => Promise<IRiskSchema[]>;
|
|
5819
|
+
}
|
|
5820
|
+
|
|
3401
5821
|
declare const backtest: {
|
|
3402
5822
|
exchangeValidationService: ExchangeValidationService;
|
|
3403
5823
|
strategyValidationService: StrategyValidationService;
|
|
3404
5824
|
frameValidationService: FrameValidationService;
|
|
5825
|
+
walkerValidationService: WalkerValidationService;
|
|
5826
|
+
sizingValidationService: SizingValidationService;
|
|
5827
|
+
riskValidationService: RiskValidationService;
|
|
3405
5828
|
backtestMarkdownService: BacktestMarkdownService;
|
|
3406
5829
|
liveMarkdownService: LiveMarkdownService;
|
|
3407
5830
|
performanceMarkdownService: PerformanceMarkdownService;
|
|
5831
|
+
walkerMarkdownService: WalkerMarkdownService;
|
|
5832
|
+
heatMarkdownService: HeatMarkdownService;
|
|
3408
5833
|
backtestLogicPublicService: BacktestLogicPublicService;
|
|
3409
5834
|
liveLogicPublicService: LiveLogicPublicService;
|
|
5835
|
+
walkerLogicPublicService: WalkerLogicPublicService;
|
|
3410
5836
|
backtestLogicPrivateService: BacktestLogicPrivateService;
|
|
3411
5837
|
liveLogicPrivateService: LiveLogicPrivateService;
|
|
5838
|
+
walkerLogicPrivateService: WalkerLogicPrivateService;
|
|
3412
5839
|
exchangeGlobalService: ExchangeGlobalService;
|
|
3413
5840
|
strategyGlobalService: StrategyGlobalService;
|
|
3414
5841
|
frameGlobalService: FrameGlobalService;
|
|
3415
5842
|
liveGlobalService: LiveGlobalService;
|
|
3416
5843
|
backtestGlobalService: BacktestGlobalService;
|
|
5844
|
+
walkerGlobalService: WalkerGlobalService;
|
|
5845
|
+
sizingGlobalService: SizingGlobalService;
|
|
5846
|
+
riskGlobalService: RiskGlobalService;
|
|
3417
5847
|
exchangeSchemaService: ExchangeSchemaService;
|
|
3418
5848
|
strategySchemaService: StrategySchemaService;
|
|
3419
5849
|
frameSchemaService: FrameSchemaService;
|
|
5850
|
+
walkerSchemaService: WalkerSchemaService;
|
|
5851
|
+
sizingSchemaService: SizingSchemaService;
|
|
5852
|
+
riskSchemaService: RiskSchemaService;
|
|
3420
5853
|
exchangeConnectionService: ExchangeConnectionService;
|
|
3421
5854
|
strategyConnectionService: StrategyConnectionService;
|
|
3422
5855
|
frameConnectionService: FrameConnectionService;
|
|
5856
|
+
sizingConnectionService: SizingConnectionService;
|
|
5857
|
+
riskConnectionService: RiskConnectionService;
|
|
3423
5858
|
executionContextService: {
|
|
3424
5859
|
readonly context: IExecutionContext;
|
|
3425
5860
|
};
|
|
@@ -3429,4 +5864,4 @@ declare const backtest: {
|
|
|
3429
5864
|
loggerService: LoggerService;
|
|
3430
5865
|
};
|
|
3431
5866
|
|
|
3432
|
-
export { Backtest, type BacktestStatistics, type CandleInterval, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type ICandleData, type IExchangeSchema, type IFrameSchema, type IPersistBase, type ISignalDto, type ISignalRow, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, Live, type LiveStatistics, MethodContextService, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistSignalAdaper, type ProgressContract, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, addExchange, addFrame, addStrategy, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listStrategies,
|
|
5867
|
+
export { Backtest, type BacktestStatistics, type CandleInterval, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, MethodContextService, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistRiskAdapter, PersistSignalAdaper, PositionSize, type ProgressContract, type RiskData, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listRisks, listSizings, listStrategies, listWalkers, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenPerformance, listenProgress, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, setLogger };
|