backtest-kit 1.1.7 → 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 +809 -841
- package/build/index.cjs +4404 -577
- package/build/index.mjs +4383 -577
- package/package.json +2 -2
- package/types.d.ts +3259 -486
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[]>;
|
|
@@ -751,12 +1507,108 @@ declare function listStrategies(): Promise<IStrategySchema[]>;
|
|
|
751
1507
|
* endDate: new Date("2024-01-02T00:00:00Z"),
|
|
752
1508
|
* });
|
|
753
1509
|
*
|
|
754
|
-
* const frames = listFrames();
|
|
755
|
-
* console.log(frames);
|
|
756
|
-
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
1510
|
+
* const frames = listFrames();
|
|
1511
|
+
* console.log(frames);
|
|
1512
|
+
* // [{ frameName: "1d-backtest", note: "One day backtest...", ... }]
|
|
1513
|
+
* ```
|
|
1514
|
+
*/
|
|
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
|
+
* // ]
|
|
757
1609
|
* ```
|
|
758
1610
|
*/
|
|
759
|
-
declare function
|
|
1611
|
+
declare function listRisks(): Promise<IRiskSchema[]>;
|
|
760
1612
|
|
|
761
1613
|
/**
|
|
762
1614
|
* Contract for background execution completion events.
|
|
@@ -819,6 +1671,84 @@ interface ProgressContract {
|
|
|
819
1671
|
progress: number;
|
|
820
1672
|
}
|
|
821
1673
|
|
|
1674
|
+
/**
|
|
1675
|
+
* Performance metric types tracked by the system.
|
|
1676
|
+
*
|
|
1677
|
+
* Backtest metrics:
|
|
1678
|
+
* - backtest_total: Total backtest duration from start to finish
|
|
1679
|
+
* - backtest_timeframe: Duration to process a single timeframe iteration
|
|
1680
|
+
* - backtest_signal: Duration to process a signal (tick + getNextCandles + backtest)
|
|
1681
|
+
*
|
|
1682
|
+
* Live metrics:
|
|
1683
|
+
* - live_tick: Duration of a single live tick iteration
|
|
1684
|
+
*/
|
|
1685
|
+
type PerformanceMetricType = "backtest_total" | "backtest_timeframe" | "backtest_signal" | "live_tick";
|
|
1686
|
+
/**
|
|
1687
|
+
* Contract for performance tracking events.
|
|
1688
|
+
*
|
|
1689
|
+
* Emitted during execution to track performance metrics for various operations.
|
|
1690
|
+
* Useful for profiling and identifying bottlenecks.
|
|
1691
|
+
*
|
|
1692
|
+
* @example
|
|
1693
|
+
* ```typescript
|
|
1694
|
+
* import { listenPerformance } from "backtest-kit";
|
|
1695
|
+
*
|
|
1696
|
+
* listenPerformance((event) => {
|
|
1697
|
+
* console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
1698
|
+
* console.log(`${event.strategyName} @ ${event.exchangeName}`);
|
|
1699
|
+
* });
|
|
1700
|
+
* ```
|
|
1701
|
+
*/
|
|
1702
|
+
interface PerformanceContract {
|
|
1703
|
+
/** Timestamp when the metric was recorded (milliseconds since epoch) */
|
|
1704
|
+
timestamp: number;
|
|
1705
|
+
/** Timestamp of the previous event (milliseconds since epoch, null for first event) */
|
|
1706
|
+
previousTimestamp: number | null;
|
|
1707
|
+
/** Type of operation being measured */
|
|
1708
|
+
metricType: PerformanceMetricType;
|
|
1709
|
+
/** Duration of the operation in milliseconds */
|
|
1710
|
+
duration: number;
|
|
1711
|
+
/** Strategy name associated with this metric */
|
|
1712
|
+
strategyName: string;
|
|
1713
|
+
/** Exchange name associated with this metric */
|
|
1714
|
+
exchangeName: string;
|
|
1715
|
+
/** Trading symbol associated with this metric */
|
|
1716
|
+
symbol: string;
|
|
1717
|
+
/** Whether this metric is from backtest mode (true) or live mode (false) */
|
|
1718
|
+
backtest: boolean;
|
|
1719
|
+
}
|
|
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
|
+
|
|
822
1752
|
/**
|
|
823
1753
|
* Subscribes to all signal events with queued async processing.
|
|
824
1754
|
*
|
|
@@ -989,9 +1919,9 @@ declare function listenSignalBacktestOnce(filterFn: (event: IStrategyTickResult)
|
|
|
989
1919
|
*/
|
|
990
1920
|
declare function listenError(fn: (error: Error) => void): () => void;
|
|
991
1921
|
/**
|
|
992
|
-
* Subscribes to background execution completion events with queued async processing.
|
|
1922
|
+
* Subscribes to live background execution completion events with queued async processing.
|
|
993
1923
|
*
|
|
994
|
-
* Emits when Live.background()
|
|
1924
|
+
* Emits when Live.background() completes execution.
|
|
995
1925
|
* Events are processed sequentially in order received, even if callback is async.
|
|
996
1926
|
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
997
1927
|
*
|
|
@@ -1000,29 +1930,82 @@ declare function listenError(fn: (error: Error) => void): () => void;
|
|
|
1000
1930
|
*
|
|
1001
1931
|
* @example
|
|
1002
1932
|
* ```typescript
|
|
1003
|
-
* import {
|
|
1933
|
+
* import { listenDoneLive, Live } from "backtest-kit";
|
|
1004
1934
|
*
|
|
1005
|
-
* const unsubscribe =
|
|
1006
|
-
* console.log("
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
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"
|
|
1010
1942
|
* });
|
|
1011
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
|
+
*
|
|
1012
1969
|
* Live.background("BTCUSDT", {
|
|
1013
1970
|
* strategyName: "my-strategy",
|
|
1014
1971
|
* exchangeName: "binance"
|
|
1015
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
|
+
* });
|
|
1016
1999
|
*
|
|
1017
2000
|
* // Later: stop listening
|
|
1018
2001
|
* unsubscribe();
|
|
1019
2002
|
* ```
|
|
1020
2003
|
*/
|
|
1021
|
-
declare function
|
|
2004
|
+
declare function listenDoneBacktest(fn: (event: DoneContract) => void): () => void;
|
|
1022
2005
|
/**
|
|
1023
|
-
* Subscribes to filtered background execution completion events with one-time execution.
|
|
2006
|
+
* Subscribes to filtered backtest background execution completion events with one-time execution.
|
|
1024
2007
|
*
|
|
1025
|
-
* Emits when
|
|
2008
|
+
* Emits when Backtest.background() completes execution.
|
|
1026
2009
|
* Executes callback once and automatically unsubscribes.
|
|
1027
2010
|
*
|
|
1028
2011
|
* @param filterFn - Predicate to filter which events trigger the callback
|
|
@@ -1031,11 +2014,11 @@ declare function listenDone(fn: (event: DoneContract) => void): () => void;
|
|
|
1031
2014
|
*
|
|
1032
2015
|
* @example
|
|
1033
2016
|
* ```typescript
|
|
1034
|
-
* import {
|
|
2017
|
+
* import { listenDoneBacktestOnce, Backtest } from "backtest-kit";
|
|
1035
2018
|
*
|
|
1036
2019
|
* // Wait for first backtest completion
|
|
1037
|
-
*
|
|
1038
|
-
* (event) => event.
|
|
2020
|
+
* listenDoneBacktestOnce(
|
|
2021
|
+
* (event) => event.symbol === "BTCUSDT",
|
|
1039
2022
|
* (event) => console.log("BTCUSDT backtest completed:", event.strategyName)
|
|
1040
2023
|
* );
|
|
1041
2024
|
*
|
|
@@ -1046,7 +2029,60 @@ declare function listenDone(fn: (event: DoneContract) => void): () => void;
|
|
|
1046
2029
|
* });
|
|
1047
2030
|
* ```
|
|
1048
2031
|
*/
|
|
1049
|
-
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;
|
|
1050
2086
|
/**
|
|
1051
2087
|
* Subscribes to backtest progress events with queued async processing.
|
|
1052
2088
|
*
|
|
@@ -1078,6 +2114,167 @@ declare function listenDoneOnce(filterFn: (event: DoneContract) => boolean, fn:
|
|
|
1078
2114
|
* ```
|
|
1079
2115
|
*/
|
|
1080
2116
|
declare function listenProgress(fn: (event: ProgressContract) => void): () => void;
|
|
2117
|
+
/**
|
|
2118
|
+
* Subscribes to performance metric events with queued async processing.
|
|
2119
|
+
*
|
|
2120
|
+
* Emits during strategy execution to track timing metrics for operations.
|
|
2121
|
+
* Useful for profiling and identifying performance bottlenecks.
|
|
2122
|
+
* Events are processed sequentially in order received, even if callback is async.
|
|
2123
|
+
* Uses queued wrapper to prevent concurrent execution of the callback.
|
|
2124
|
+
*
|
|
2125
|
+
* @param fn - Callback function to handle performance events
|
|
2126
|
+
* @returns Unsubscribe function to stop listening to events
|
|
2127
|
+
*
|
|
2128
|
+
* @example
|
|
2129
|
+
* ```typescript
|
|
2130
|
+
* import { listenPerformance, Backtest } from "backtest-kit";
|
|
2131
|
+
*
|
|
2132
|
+
* const unsubscribe = listenPerformance((event) => {
|
|
2133
|
+
* console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
2134
|
+
* if (event.duration > 100) {
|
|
2135
|
+
* console.warn("Slow operation detected:", event.metricType);
|
|
2136
|
+
* }
|
|
2137
|
+
* });
|
|
2138
|
+
*
|
|
2139
|
+
* Backtest.background("BTCUSDT", {
|
|
2140
|
+
* strategyName: "my-strategy",
|
|
2141
|
+
* exchangeName: "binance",
|
|
2142
|
+
* frameName: "1d-backtest"
|
|
2143
|
+
* });
|
|
2144
|
+
*
|
|
2145
|
+
* // Later: stop listening
|
|
2146
|
+
* unsubscribe();
|
|
2147
|
+
* ```
|
|
2148
|
+
*/
|
|
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;
|
|
1081
2278
|
|
|
1082
2279
|
/**
|
|
1083
2280
|
* Fetches historical candle data from the registered exchange.
|
|
@@ -1181,39 +2378,131 @@ declare function getDate(): Promise<Date>;
|
|
|
1181
2378
|
declare function getMode(): Promise<"backtest" | "live">;
|
|
1182
2379
|
|
|
1183
2380
|
/**
|
|
1184
|
-
*
|
|
2381
|
+
* Portfolio heatmap statistics for a single symbol.
|
|
2382
|
+
* Aggregated metrics across all strategies for one trading pair.
|
|
2383
|
+
*/
|
|
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 */
|
|
2396
|
+
winCount: number;
|
|
2397
|
+
/** Number of losing trades */
|
|
2398
|
+
lossCount: number;
|
|
2399
|
+
/** Win rate percentage */
|
|
2400
|
+
winRate: number | null;
|
|
2401
|
+
/** Average PNL per trade */
|
|
2402
|
+
avgPnl: number | null;
|
|
2403
|
+
/** Standard deviation of PNL */
|
|
2404
|
+
stdDev: number | null;
|
|
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;
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Portfolio heatmap statistics structure.
|
|
2420
|
+
* Contains aggregated data for all symbols in the portfolio.
|
|
2421
|
+
*/
|
|
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;
|
|
2433
|
+
}
|
|
2434
|
+
|
|
2435
|
+
/**
|
|
2436
|
+
* Unified tick event data for report generation.
|
|
2437
|
+
* Contains all information about a tick event regardless of action type.
|
|
2438
|
+
*/
|
|
2439
|
+
interface TickEvent {
|
|
2440
|
+
/** Event timestamp in milliseconds */
|
|
2441
|
+
timestamp: number;
|
|
2442
|
+
/** Event action type */
|
|
2443
|
+
action: "idle" | "opened" | "active" | "closed";
|
|
2444
|
+
/** Trading pair symbol (only for non-idle events) */
|
|
2445
|
+
symbol?: string;
|
|
2446
|
+
/** Signal ID (only for opened/active/closed) */
|
|
2447
|
+
signalId?: string;
|
|
2448
|
+
/** Position type (only for opened/active/closed) */
|
|
2449
|
+
position?: string;
|
|
2450
|
+
/** Signal note (only for opened/active/closed) */
|
|
2451
|
+
note?: string;
|
|
2452
|
+
/** Current price */
|
|
2453
|
+
currentPrice: number;
|
|
2454
|
+
/** Open price (only for opened/active/closed) */
|
|
2455
|
+
openPrice?: number;
|
|
2456
|
+
/** Take profit price (only for opened/active/closed) */
|
|
2457
|
+
takeProfit?: number;
|
|
2458
|
+
/** Stop loss price (only for opened/active/closed) */
|
|
2459
|
+
stopLoss?: number;
|
|
2460
|
+
/** PNL percentage (only for closed) */
|
|
2461
|
+
pnl?: number;
|
|
2462
|
+
/** Close reason (only for closed) */
|
|
2463
|
+
closeReason?: string;
|
|
2464
|
+
/** Duration in minutes (only for closed) */
|
|
2465
|
+
duration?: number;
|
|
2466
|
+
}
|
|
2467
|
+
/**
|
|
2468
|
+
* Statistical data calculated from live trading results.
|
|
1185
2469
|
*
|
|
1186
2470
|
* All numeric values are null if calculation is unsafe (NaN, Infinity, etc).
|
|
1187
|
-
* Provides comprehensive metrics for
|
|
2471
|
+
* Provides comprehensive metrics for live trading performance analysis.
|
|
1188
2472
|
*
|
|
1189
2473
|
* @example
|
|
1190
2474
|
* ```typescript
|
|
1191
|
-
* const stats = await
|
|
2475
|
+
* const stats = await Live.getData("my-strategy");
|
|
1192
2476
|
*
|
|
1193
|
-
* console.log(`Total
|
|
2477
|
+
* console.log(`Total events: ${stats.totalEvents}`);
|
|
2478
|
+
* console.log(`Closed signals: ${stats.totalClosed}`);
|
|
1194
2479
|
* console.log(`Win rate: ${stats.winRate}%`);
|
|
1195
2480
|
* console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
|
|
1196
2481
|
*
|
|
1197
|
-
* // Access raw
|
|
1198
|
-
* stats.
|
|
1199
|
-
*
|
|
2482
|
+
* // Access raw event data (includes idle, opened, active, closed)
|
|
2483
|
+
* stats.eventList.forEach(event => {
|
|
2484
|
+
* if (event.action === "closed") {
|
|
2485
|
+
* console.log(`Closed signal: ${event.pnl}%`);
|
|
2486
|
+
* }
|
|
1200
2487
|
* });
|
|
1201
2488
|
* ```
|
|
1202
2489
|
*/
|
|
1203
|
-
interface
|
|
1204
|
-
/** Array of all
|
|
1205
|
-
|
|
1206
|
-
/** Total number of closed
|
|
1207
|
-
|
|
1208
|
-
/**
|
|
2490
|
+
interface LiveStatistics {
|
|
2491
|
+
/** Array of all events (idle, opened, active, closed) with full details */
|
|
2492
|
+
eventList: TickEvent[];
|
|
2493
|
+
/** Total number of all events (includes idle, opened, active, closed) */
|
|
2494
|
+
totalEvents: number;
|
|
2495
|
+
/** Total number of closed signals only */
|
|
2496
|
+
totalClosed: number;
|
|
2497
|
+
/** Number of winning closed signals (PNL > 0) */
|
|
1209
2498
|
winCount: number;
|
|
1210
|
-
/** Number of losing signals (PNL < 0) */
|
|
2499
|
+
/** Number of losing closed signals (PNL < 0) */
|
|
1211
2500
|
lossCount: number;
|
|
1212
|
-
/** Win rate as percentage (0-100), null if unsafe. Higher is better. */
|
|
2501
|
+
/** Win rate as percentage (0-100) based on closed signals, null if unsafe. Higher is better. */
|
|
1213
2502
|
winRate: number | null;
|
|
1214
|
-
/** Average PNL per signal as percentage, null if unsafe. Higher is better. */
|
|
2503
|
+
/** Average PNL per closed signal as percentage, null if unsafe. Higher is better. */
|
|
1215
2504
|
avgPnl: number | null;
|
|
1216
|
-
/** Cumulative PNL across all signals as percentage, null if unsafe. Higher is better. */
|
|
2505
|
+
/** Cumulative PNL across all closed signals as percentage, null if unsafe. Higher is better. */
|
|
1217
2506
|
totalPnl: number | null;
|
|
1218
2507
|
/** Standard deviation of returns (volatility metric), null if unsafe. Lower is better. */
|
|
1219
2508
|
stdDev: number | null;
|
|
@@ -1227,33 +2516,36 @@ interface BacktestStatistics {
|
|
|
1227
2516
|
expectedYearlyReturns: number | null;
|
|
1228
2517
|
}
|
|
1229
2518
|
/**
|
|
1230
|
-
* Service for generating and saving
|
|
2519
|
+
* Service for generating and saving live trading markdown reports.
|
|
1231
2520
|
*
|
|
1232
2521
|
* Features:
|
|
1233
|
-
* - Listens to signal events via onTick callback
|
|
1234
|
-
* - Accumulates
|
|
1235
|
-
* - Generates markdown tables with detailed
|
|
1236
|
-
* -
|
|
2522
|
+
* - Listens to all signal events via onTick callback
|
|
2523
|
+
* - Accumulates all events (idle, opened, active, closed) per strategy
|
|
2524
|
+
* - Generates markdown tables with detailed event information
|
|
2525
|
+
* - Provides trading statistics (win rate, average PNL)
|
|
2526
|
+
* - Saves reports to disk in logs/live/{strategyName}.md
|
|
1237
2527
|
*
|
|
1238
2528
|
* @example
|
|
1239
2529
|
* ```typescript
|
|
1240
|
-
* const service = new
|
|
2530
|
+
* const service = new LiveMarkdownService();
|
|
1241
2531
|
*
|
|
1242
2532
|
* // Add to strategy callbacks
|
|
1243
2533
|
* addStrategy({
|
|
1244
2534
|
* strategyName: "my-strategy",
|
|
1245
2535
|
* callbacks: {
|
|
1246
2536
|
* onTick: (symbol, result, backtest) => {
|
|
1247
|
-
*
|
|
2537
|
+
* if (!backtest) {
|
|
2538
|
+
* service.tick(result);
|
|
2539
|
+
* }
|
|
1248
2540
|
* }
|
|
1249
2541
|
* }
|
|
1250
2542
|
* });
|
|
1251
2543
|
*
|
|
1252
|
-
* //
|
|
1253
|
-
* await service.
|
|
2544
|
+
* // Later: generate and save report
|
|
2545
|
+
* await service.dump("my-strategy");
|
|
1254
2546
|
* ```
|
|
1255
2547
|
*/
|
|
1256
|
-
declare class
|
|
2548
|
+
declare class LiveMarkdownService {
|
|
1257
2549
|
/** Logger service for debug output */
|
|
1258
2550
|
private readonly loggerService;
|
|
1259
2551
|
/**
|
|
@@ -1262,27 +2554,29 @@ declare class BacktestMarkdownService {
|
|
|
1262
2554
|
*/
|
|
1263
2555
|
private getStorage;
|
|
1264
2556
|
/**
|
|
1265
|
-
* Processes tick events and accumulates
|
|
2557
|
+
* Processes tick events and accumulates all event types.
|
|
1266
2558
|
* Should be called from IStrategyCallbacks.onTick.
|
|
1267
2559
|
*
|
|
1268
|
-
*
|
|
2560
|
+
* Processes all event types: idle, opened, active, closed.
|
|
1269
2561
|
*
|
|
1270
|
-
* @param data - Tick result from strategy execution
|
|
2562
|
+
* @param data - Tick result from strategy execution
|
|
1271
2563
|
*
|
|
1272
2564
|
* @example
|
|
1273
2565
|
* ```typescript
|
|
1274
|
-
* const service = new
|
|
2566
|
+
* const service = new LiveMarkdownService();
|
|
1275
2567
|
*
|
|
1276
2568
|
* callbacks: {
|
|
1277
2569
|
* onTick: (symbol, result, backtest) => {
|
|
1278
|
-
*
|
|
2570
|
+
* if (!backtest) {
|
|
2571
|
+
* service.tick(result);
|
|
2572
|
+
* }
|
|
1279
2573
|
* }
|
|
1280
2574
|
* }
|
|
1281
2575
|
* ```
|
|
1282
2576
|
*/
|
|
1283
2577
|
private tick;
|
|
1284
2578
|
/**
|
|
1285
|
-
* Gets statistical data from all
|
|
2579
|
+
* Gets statistical data from all live trading events for a strategy.
|
|
1286
2580
|
* Delegates to ReportStorage.getData().
|
|
1287
2581
|
*
|
|
1288
2582
|
* @param strategyName - Strategy name to get data for
|
|
@@ -1290,22 +2584,22 @@ declare class BacktestMarkdownService {
|
|
|
1290
2584
|
*
|
|
1291
2585
|
* @example
|
|
1292
2586
|
* ```typescript
|
|
1293
|
-
* const service = new
|
|
2587
|
+
* const service = new LiveMarkdownService();
|
|
1294
2588
|
* const stats = await service.getData("my-strategy");
|
|
1295
2589
|
* console.log(stats.sharpeRatio, stats.winRate);
|
|
1296
2590
|
* ```
|
|
1297
2591
|
*/
|
|
1298
|
-
getData: (strategyName: StrategyName) => Promise<
|
|
2592
|
+
getData: (strategyName: StrategyName) => Promise<LiveStatistics>;
|
|
1299
2593
|
/**
|
|
1300
|
-
* Generates markdown report with all
|
|
1301
|
-
* Delegates to ReportStorage.
|
|
2594
|
+
* Generates markdown report with all events for a strategy.
|
|
2595
|
+
* Delegates to ReportStorage.getReport().
|
|
1302
2596
|
*
|
|
1303
2597
|
* @param strategyName - Strategy name to generate report for
|
|
1304
|
-
* @returns Markdown formatted report string with table of all
|
|
2598
|
+
* @returns Markdown formatted report string with table of all events
|
|
1305
2599
|
*
|
|
1306
2600
|
* @example
|
|
1307
2601
|
* ```typescript
|
|
1308
|
-
* const service = new
|
|
2602
|
+
* const service = new LiveMarkdownService();
|
|
1309
2603
|
* const markdown = await service.getReport("my-strategy");
|
|
1310
2604
|
* console.log(markdown);
|
|
1311
2605
|
* ```
|
|
@@ -1317,13 +2611,13 @@ declare class BacktestMarkdownService {
|
|
|
1317
2611
|
* Delegates to ReportStorage.dump().
|
|
1318
2612
|
*
|
|
1319
2613
|
* @param strategyName - Strategy name to save report for
|
|
1320
|
-
* @param path - Directory path to save report (default: "./logs/
|
|
2614
|
+
* @param path - Directory path to save report (default: "./logs/live")
|
|
1321
2615
|
*
|
|
1322
2616
|
* @example
|
|
1323
2617
|
* ```typescript
|
|
1324
|
-
* const service = new
|
|
2618
|
+
* const service = new LiveMarkdownService();
|
|
1325
2619
|
*
|
|
1326
|
-
* // Save to default path: ./logs/
|
|
2620
|
+
* // Save to default path: ./logs/live/my-strategy.md
|
|
1327
2621
|
* await service.dump("my-strategy");
|
|
1328
2622
|
*
|
|
1329
2623
|
* // Save to custom path: ./custom/path/my-strategy.md
|
|
@@ -1332,7 +2626,7 @@ declare class BacktestMarkdownService {
|
|
|
1332
2626
|
*/
|
|
1333
2627
|
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
1334
2628
|
/**
|
|
1335
|
-
* Clears accumulated
|
|
2629
|
+
* Clears accumulated event data from storage.
|
|
1336
2630
|
* If strategyName is provided, clears only that strategy's data.
|
|
1337
2631
|
* If strategyName is omitted, clears all strategies' data.
|
|
1338
2632
|
*
|
|
@@ -1340,7 +2634,7 @@ declare class BacktestMarkdownService {
|
|
|
1340
2634
|
*
|
|
1341
2635
|
* @example
|
|
1342
2636
|
* ```typescript
|
|
1343
|
-
* const service = new
|
|
2637
|
+
* const service = new LiveMarkdownService();
|
|
1344
2638
|
*
|
|
1345
2639
|
* // Clear specific strategy data
|
|
1346
2640
|
* await service.clear("my-strategy");
|
|
@@ -1351,240 +2645,303 @@ declare class BacktestMarkdownService {
|
|
|
1351
2645
|
*/
|
|
1352
2646
|
clear: (strategyName?: StrategyName) => Promise<void>;
|
|
1353
2647
|
/**
|
|
1354
|
-
* Initializes the service by subscribing to
|
|
2648
|
+
* Initializes the service by subscribing to live signal events.
|
|
1355
2649
|
* Uses singleshot to ensure initialization happens only once.
|
|
1356
2650
|
* Automatically called on first use.
|
|
1357
2651
|
*
|
|
1358
2652
|
* @example
|
|
1359
2653
|
* ```typescript
|
|
1360
|
-
* const service = new
|
|
1361
|
-
* await service.init(); // Subscribe to
|
|
2654
|
+
* const service = new LiveMarkdownService();
|
|
2655
|
+
* await service.init(); // Subscribe to live events
|
|
1362
2656
|
* ```
|
|
1363
2657
|
*/
|
|
1364
2658
|
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
1365
2659
|
}
|
|
1366
2660
|
|
|
1367
2661
|
/**
|
|
1368
|
-
*
|
|
1369
|
-
* Contains all information about a tick event regardless of action type.
|
|
2662
|
+
* Aggregated statistics for a specific metric type.
|
|
1370
2663
|
*/
|
|
1371
|
-
interface
|
|
1372
|
-
/**
|
|
1373
|
-
|
|
1374
|
-
/**
|
|
1375
|
-
|
|
1376
|
-
/**
|
|
1377
|
-
|
|
1378
|
-
/**
|
|
1379
|
-
|
|
1380
|
-
/**
|
|
1381
|
-
|
|
1382
|
-
/**
|
|
1383
|
-
|
|
1384
|
-
/**
|
|
1385
|
-
|
|
1386
|
-
/**
|
|
1387
|
-
|
|
1388
|
-
/**
|
|
1389
|
-
|
|
1390
|
-
/**
|
|
1391
|
-
|
|
1392
|
-
/**
|
|
1393
|
-
|
|
1394
|
-
/**
|
|
1395
|
-
|
|
1396
|
-
/**
|
|
1397
|
-
|
|
2664
|
+
interface MetricStats {
|
|
2665
|
+
/** Type of metric */
|
|
2666
|
+
metricType: PerformanceMetricType;
|
|
2667
|
+
/** Number of recorded samples */
|
|
2668
|
+
count: number;
|
|
2669
|
+
/** Total duration across all samples (ms) */
|
|
2670
|
+
totalDuration: number;
|
|
2671
|
+
/** Average duration (ms) */
|
|
2672
|
+
avgDuration: number;
|
|
2673
|
+
/** Minimum duration (ms) */
|
|
2674
|
+
minDuration: number;
|
|
2675
|
+
/** Maximum duration (ms) */
|
|
2676
|
+
maxDuration: number;
|
|
2677
|
+
/** Standard deviation of duration (ms) */
|
|
2678
|
+
stdDev: number;
|
|
2679
|
+
/** Median duration (ms) */
|
|
2680
|
+
median: number;
|
|
2681
|
+
/** 95th percentile duration (ms) */
|
|
2682
|
+
p95: number;
|
|
2683
|
+
/** 99th percentile duration (ms) */
|
|
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;
|
|
1398
2691
|
}
|
|
1399
2692
|
/**
|
|
1400
|
-
*
|
|
2693
|
+
* Performance statistics aggregated by strategy.
|
|
2694
|
+
*/
|
|
2695
|
+
interface PerformanceStatistics {
|
|
2696
|
+
/** Strategy name */
|
|
2697
|
+
strategyName: string;
|
|
2698
|
+
/** Total number of performance events recorded */
|
|
2699
|
+
totalEvents: number;
|
|
2700
|
+
/** Total execution time across all metrics (ms) */
|
|
2701
|
+
totalDuration: number;
|
|
2702
|
+
/** Statistics grouped by metric type */
|
|
2703
|
+
metricStats: Record<string, MetricStats>;
|
|
2704
|
+
/** All raw performance events */
|
|
2705
|
+
events: PerformanceContract[];
|
|
2706
|
+
}
|
|
2707
|
+
/**
|
|
2708
|
+
* Service for collecting and analyzing performance metrics.
|
|
1401
2709
|
*
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
2710
|
+
* Features:
|
|
2711
|
+
* - Listens to performance events via performanceEmitter
|
|
2712
|
+
* - Accumulates metrics per strategy
|
|
2713
|
+
* - Calculates aggregated statistics (avg, min, max, percentiles)
|
|
2714
|
+
* - Generates markdown reports with bottleneck analysis
|
|
2715
|
+
* - Saves reports to disk in logs/performance/{strategyName}.md
|
|
1404
2716
|
*
|
|
1405
2717
|
* @example
|
|
1406
2718
|
* ```typescript
|
|
1407
|
-
*
|
|
1408
|
-
*
|
|
1409
|
-
* console.log(`Total events: ${stats.totalEvents}`);
|
|
1410
|
-
* console.log(`Closed signals: ${stats.totalClosed}`);
|
|
1411
|
-
* console.log(`Win rate: ${stats.winRate}%`);
|
|
1412
|
-
* console.log(`Sharpe Ratio: ${stats.sharpeRatio}`);
|
|
2719
|
+
* import { listenPerformance } from "backtest-kit";
|
|
1413
2720
|
*
|
|
1414
|
-
* //
|
|
1415
|
-
*
|
|
1416
|
-
*
|
|
1417
|
-
* console.log(`Closed signal: ${event.pnl}%`);
|
|
1418
|
-
* }
|
|
2721
|
+
* // Subscribe to performance events
|
|
2722
|
+
* listenPerformance((event) => {
|
|
2723
|
+
* console.log(`${event.metricType}: ${event.duration.toFixed(2)}ms`);
|
|
1419
2724
|
* });
|
|
2725
|
+
*
|
|
2726
|
+
* // After execution, generate report
|
|
2727
|
+
* const stats = await Performance.getData("my-strategy");
|
|
2728
|
+
* console.log("Bottlenecks:", stats.metricStats);
|
|
2729
|
+
*
|
|
2730
|
+
* // Save report to disk
|
|
2731
|
+
* await Performance.dump("my-strategy");
|
|
1420
2732
|
* ```
|
|
1421
2733
|
*/
|
|
1422
|
-
|
|
1423
|
-
/**
|
|
1424
|
-
|
|
1425
|
-
/**
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
/**
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
2734
|
+
declare class PerformanceMarkdownService {
|
|
2735
|
+
/** Logger service for debug output */
|
|
2736
|
+
private readonly loggerService;
|
|
2737
|
+
/**
|
|
2738
|
+
* Memoized function to get or create PerformanceStorage for a strategy.
|
|
2739
|
+
* Each strategy gets its own isolated storage instance.
|
|
2740
|
+
*/
|
|
2741
|
+
private getStorage;
|
|
2742
|
+
/**
|
|
2743
|
+
* Processes performance events and accumulates metrics.
|
|
2744
|
+
* Should be called from performance tracking code.
|
|
2745
|
+
*
|
|
2746
|
+
* @param event - Performance event with timing data
|
|
2747
|
+
*/
|
|
2748
|
+
private track;
|
|
2749
|
+
/**
|
|
2750
|
+
* Gets aggregated performance statistics for a strategy.
|
|
2751
|
+
*
|
|
2752
|
+
* @param strategyName - Strategy name to get data for
|
|
2753
|
+
* @returns Performance statistics with aggregated metrics
|
|
2754
|
+
*
|
|
2755
|
+
* @example
|
|
2756
|
+
* ```typescript
|
|
2757
|
+
* const stats = await performanceService.getData("my-strategy");
|
|
2758
|
+
* console.log("Total time:", stats.totalDuration);
|
|
2759
|
+
* console.log("Slowest operation:", Object.values(stats.metricStats)
|
|
2760
|
+
* .sort((a, b) => b.avgDuration - a.avgDuration)[0]);
|
|
2761
|
+
* ```
|
|
2762
|
+
*/
|
|
2763
|
+
getData: (strategyName: string) => Promise<PerformanceStatistics>;
|
|
2764
|
+
/**
|
|
2765
|
+
* Generates markdown report with performance analysis.
|
|
2766
|
+
*
|
|
2767
|
+
* @param strategyName - Strategy name to generate report for
|
|
2768
|
+
* @returns Markdown formatted report string
|
|
2769
|
+
*
|
|
2770
|
+
* @example
|
|
2771
|
+
* ```typescript
|
|
2772
|
+
* const markdown = await performanceService.getReport("my-strategy");
|
|
2773
|
+
* console.log(markdown);
|
|
2774
|
+
* ```
|
|
2775
|
+
*/
|
|
2776
|
+
getReport: (strategyName: string) => Promise<string>;
|
|
2777
|
+
/**
|
|
2778
|
+
* Saves performance report to disk.
|
|
2779
|
+
*
|
|
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;
|
|
1449
2804
|
}
|
|
2805
|
+
|
|
1450
2806
|
/**
|
|
1451
|
-
*
|
|
1452
|
-
*
|
|
1453
|
-
* Features:
|
|
1454
|
-
* - Listens to all signal events via onTick callback
|
|
1455
|
-
* - Accumulates all events (idle, opened, active, closed) per strategy
|
|
1456
|
-
* - Generates markdown tables with detailed event information
|
|
1457
|
-
* - Provides trading statistics (win rate, average PNL)
|
|
1458
|
-
* - Saves reports to disk in logs/live/{strategyName}.md
|
|
2807
|
+
* Alias for walker statistics result interface.
|
|
2808
|
+
* Used for clarity in markdown service context.
|
|
1459
2809
|
*
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
2810
|
+
*/
|
|
2811
|
+
type WalkerStatistics = IWalkerResults;
|
|
2812
|
+
/**
|
|
2813
|
+
* Service for generating and saving walker markdown reports.
|
|
1463
2814
|
*
|
|
1464
|
-
*
|
|
1465
|
-
*
|
|
1466
|
-
*
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
* if (!backtest) {
|
|
1470
|
-
* service.tick(result);
|
|
1471
|
-
* }
|
|
1472
|
-
* }
|
|
1473
|
-
* }
|
|
1474
|
-
* });
|
|
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
|
|
1475
2820
|
*
|
|
1476
|
-
*
|
|
1477
|
-
*
|
|
2821
|
+
* @example
|
|
2822
|
+
* ```typescript
|
|
2823
|
+
* const service = new WalkerMarkdownService();
|
|
2824
|
+
* const results = await service.getData("my-walker");
|
|
2825
|
+
* await service.dump("my-walker");
|
|
1478
2826
|
* ```
|
|
1479
2827
|
*/
|
|
1480
|
-
declare class
|
|
2828
|
+
declare class WalkerMarkdownService {
|
|
1481
2829
|
/** Logger service for debug output */
|
|
1482
2830
|
private readonly loggerService;
|
|
1483
2831
|
/**
|
|
1484
|
-
* Memoized function to get or create ReportStorage for a
|
|
1485
|
-
* Each
|
|
2832
|
+
* Memoized function to get or create ReportStorage for a walker.
|
|
2833
|
+
* Each walker gets its own isolated storage instance.
|
|
1486
2834
|
*/
|
|
1487
2835
|
private getStorage;
|
|
1488
2836
|
/**
|
|
1489
|
-
* Processes
|
|
1490
|
-
* Should be called from
|
|
1491
|
-
*
|
|
1492
|
-
* Processes all event types: idle, opened, active, closed.
|
|
2837
|
+
* Processes walker progress events and accumulates strategy results.
|
|
2838
|
+
* Should be called from walkerEmitter.
|
|
1493
2839
|
*
|
|
1494
|
-
* @param data -
|
|
2840
|
+
* @param data - Walker contract from walker execution
|
|
1495
2841
|
*
|
|
1496
2842
|
* @example
|
|
1497
2843
|
* ```typescript
|
|
1498
|
-
* const service = new
|
|
1499
|
-
*
|
|
1500
|
-
* callbacks: {
|
|
1501
|
-
* onTick: (symbol, result, backtest) => {
|
|
1502
|
-
* if (!backtest) {
|
|
1503
|
-
* service.tick(result);
|
|
1504
|
-
* }
|
|
1505
|
-
* }
|
|
1506
|
-
* }
|
|
2844
|
+
* const service = new WalkerMarkdownService();
|
|
2845
|
+
* walkerEmitter.subscribe((data) => service.tick(data));
|
|
1507
2846
|
* ```
|
|
1508
2847
|
*/
|
|
1509
2848
|
private tick;
|
|
1510
2849
|
/**
|
|
1511
|
-
* Gets
|
|
2850
|
+
* Gets walker results data from all strategy results.
|
|
1512
2851
|
* Delegates to ReportStorage.getData().
|
|
1513
2852
|
*
|
|
1514
|
-
* @param
|
|
1515
|
-
* @
|
|
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
|
|
1516
2858
|
*
|
|
1517
2859
|
* @example
|
|
1518
2860
|
* ```typescript
|
|
1519
|
-
* const service = new
|
|
1520
|
-
* const
|
|
1521
|
-
* console.log(
|
|
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);
|
|
1522
2864
|
* ```
|
|
1523
2865
|
*/
|
|
1524
|
-
getData: (
|
|
2866
|
+
getData: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2867
|
+
exchangeName: string;
|
|
2868
|
+
frameName: string;
|
|
2869
|
+
}) => Promise<IWalkerResults>;
|
|
1525
2870
|
/**
|
|
1526
|
-
* Generates markdown report with all
|
|
2871
|
+
* Generates markdown report with all strategy results for a walker.
|
|
1527
2872
|
* Delegates to ReportStorage.getReport().
|
|
1528
2873
|
*
|
|
1529
|
-
* @param
|
|
1530
|
-
* @
|
|
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
|
|
1531
2879
|
*
|
|
1532
2880
|
* @example
|
|
1533
2881
|
* ```typescript
|
|
1534
|
-
* const service = new
|
|
1535
|
-
* const markdown = await service.getReport("my-
|
|
2882
|
+
* const service = new WalkerMarkdownService();
|
|
2883
|
+
* const markdown = await service.getReport("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" });
|
|
1536
2884
|
* console.log(markdown);
|
|
1537
2885
|
* ```
|
|
1538
2886
|
*/
|
|
1539
|
-
getReport: (
|
|
2887
|
+
getReport: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2888
|
+
exchangeName: string;
|
|
2889
|
+
frameName: string;
|
|
2890
|
+
}) => Promise<string>;
|
|
1540
2891
|
/**
|
|
1541
|
-
* Saves
|
|
2892
|
+
* Saves walker report to disk.
|
|
1542
2893
|
* Creates directory if it doesn't exist.
|
|
1543
2894
|
* Delegates to ReportStorage.dump().
|
|
1544
2895
|
*
|
|
1545
|
-
* @param
|
|
1546
|
-
* @param
|
|
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")
|
|
1547
2901
|
*
|
|
1548
2902
|
* @example
|
|
1549
2903
|
* ```typescript
|
|
1550
|
-
* const service = new
|
|
2904
|
+
* const service = new WalkerMarkdownService();
|
|
1551
2905
|
*
|
|
1552
|
-
* // Save to default path: ./logs/
|
|
1553
|
-
* await service.dump("my-
|
|
2906
|
+
* // Save to default path: ./logs/walker/my-walker.md
|
|
2907
|
+
* await service.dump("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" });
|
|
1554
2908
|
*
|
|
1555
|
-
* // Save to custom path: ./custom/path/my-
|
|
1556
|
-
* await service.dump("my-
|
|
2909
|
+
* // Save to custom path: ./custom/path/my-walker.md
|
|
2910
|
+
* await service.dump("my-walker", "BTCUSDT", "sharpeRatio", { exchangeName: "binance", frameName: "1d" }, "./custom/path");
|
|
1557
2911
|
* ```
|
|
1558
2912
|
*/
|
|
1559
|
-
dump: (
|
|
2913
|
+
dump: (walkerName: WalkerName, symbol: string, metric: WalkerMetric, context: {
|
|
2914
|
+
exchangeName: string;
|
|
2915
|
+
frameName: string;
|
|
2916
|
+
}, path?: string) => Promise<void>;
|
|
1560
2917
|
/**
|
|
1561
|
-
* Clears accumulated
|
|
1562
|
-
* If
|
|
1563
|
-
* If
|
|
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.
|
|
1564
2921
|
*
|
|
1565
|
-
* @param
|
|
2922
|
+
* @param walkerName - Optional walker name to clear specific walker data
|
|
1566
2923
|
*
|
|
1567
2924
|
* @example
|
|
1568
2925
|
* ```typescript
|
|
1569
|
-
* const service = new
|
|
2926
|
+
* const service = new WalkerMarkdownService();
|
|
1570
2927
|
*
|
|
1571
|
-
* // Clear specific
|
|
1572
|
-
* await service.clear("my-
|
|
2928
|
+
* // Clear specific walker data
|
|
2929
|
+
* await service.clear("my-walker");
|
|
1573
2930
|
*
|
|
1574
|
-
* // Clear all
|
|
2931
|
+
* // Clear all walkers' data
|
|
1575
2932
|
* await service.clear();
|
|
1576
2933
|
* ```
|
|
1577
2934
|
*/
|
|
1578
|
-
clear: (
|
|
2935
|
+
clear: (walkerName?: WalkerName) => Promise<void>;
|
|
1579
2936
|
/**
|
|
1580
|
-
* Initializes the service by subscribing to
|
|
2937
|
+
* Initializes the service by subscribing to walker events.
|
|
1581
2938
|
* Uses singleshot to ensure initialization happens only once.
|
|
1582
2939
|
* Automatically called on first use.
|
|
1583
2940
|
*
|
|
1584
2941
|
* @example
|
|
1585
2942
|
* ```typescript
|
|
1586
|
-
* const service = new
|
|
1587
|
-
* await service.init(); // Subscribe to
|
|
2943
|
+
* const service = new WalkerMarkdownService();
|
|
2944
|
+
* await service.init(); // Subscribe to walker events
|
|
1588
2945
|
* ```
|
|
1589
2946
|
*/
|
|
1590
2947
|
protected init: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
@@ -1818,6 +3175,79 @@ declare class PersistSignalUtils {
|
|
|
1818
3175
|
* ```
|
|
1819
3176
|
*/
|
|
1820
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;
|
|
1821
3251
|
|
|
1822
3252
|
/**
|
|
1823
3253
|
* Utility class for backtest operations.
|
|
@@ -1992,82 +3422,600 @@ declare class LiveUtils {
|
|
|
1992
3422
|
* Useful for running live trading for side effects only (callbacks, persistence).
|
|
1993
3423
|
*
|
|
1994
3424
|
* @param symbol - Trading pair symbol (e.g., "BTCUSDT")
|
|
1995
|
-
* @param context - Execution context with strategy and exchange names
|
|
3425
|
+
* @param context - Execution context with strategy and exchange names
|
|
3426
|
+
* @returns Cancellation closure
|
|
3427
|
+
*
|
|
3428
|
+
* @example
|
|
3429
|
+
* ```typescript
|
|
3430
|
+
* // Run live trading silently in background, only callbacks will fire
|
|
3431
|
+
* // This will run forever until Ctrl+C
|
|
3432
|
+
* await Live.background("BTCUSDT", {
|
|
3433
|
+
* strategyName: "my-strategy",
|
|
3434
|
+
* exchangeName: "my-exchange"
|
|
3435
|
+
* });
|
|
3436
|
+
* ```
|
|
3437
|
+
*/
|
|
3438
|
+
background: (symbol: string, context: {
|
|
3439
|
+
strategyName: string;
|
|
3440
|
+
exchangeName: string;
|
|
3441
|
+
}) => () => void;
|
|
3442
|
+
/**
|
|
3443
|
+
* Gets statistical data from all live trading events for a strategy.
|
|
3444
|
+
*
|
|
3445
|
+
* @param strategyName - Strategy name to get data for
|
|
3446
|
+
* @returns Promise resolving to statistical data object
|
|
3447
|
+
*
|
|
3448
|
+
* @example
|
|
3449
|
+
* ```typescript
|
|
3450
|
+
* const stats = await Live.getData("my-strategy");
|
|
3451
|
+
* console.log(stats.sharpeRatio, stats.winRate);
|
|
3452
|
+
* ```
|
|
3453
|
+
*/
|
|
3454
|
+
getData: (strategyName: StrategyName) => Promise<LiveStatistics>;
|
|
3455
|
+
/**
|
|
3456
|
+
* Generates markdown report with all events for a strategy.
|
|
3457
|
+
*
|
|
3458
|
+
* @param strategyName - Strategy name to generate report for
|
|
3459
|
+
* @returns Promise resolving to markdown formatted report string
|
|
3460
|
+
*
|
|
3461
|
+
* @example
|
|
3462
|
+
* ```typescript
|
|
3463
|
+
* const markdown = await Live.getReport("my-strategy");
|
|
3464
|
+
* console.log(markdown);
|
|
3465
|
+
* ```
|
|
3466
|
+
*/
|
|
3467
|
+
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
3468
|
+
/**
|
|
3469
|
+
* Saves strategy report to disk.
|
|
3470
|
+
*
|
|
3471
|
+
* @param strategyName - Strategy name to save report for
|
|
3472
|
+
* @param path - Optional directory path to save report (default: "./logs/live")
|
|
3473
|
+
*
|
|
3474
|
+
* @example
|
|
3475
|
+
* ```typescript
|
|
3476
|
+
* // Save to default path: ./logs/live/my-strategy.md
|
|
3477
|
+
* await Live.dump("my-strategy");
|
|
3478
|
+
*
|
|
3479
|
+
* // Save to custom path: ./custom/path/my-strategy.md
|
|
3480
|
+
* await Live.dump("my-strategy", "./custom/path");
|
|
3481
|
+
* ```
|
|
3482
|
+
*/
|
|
3483
|
+
dump: (strategyName: StrategyName, path?: string) => Promise<void>;
|
|
3484
|
+
}
|
|
3485
|
+
/**
|
|
3486
|
+
* Singleton instance of LiveUtils for convenient live trading operations.
|
|
3487
|
+
*
|
|
3488
|
+
* @example
|
|
3489
|
+
* ```typescript
|
|
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
|
|
1996
3659
|
* @returns Cancellation closure
|
|
1997
3660
|
*
|
|
1998
3661
|
* @example
|
|
1999
3662
|
* ```typescript
|
|
2000
|
-
* // Run
|
|
2001
|
-
*
|
|
2002
|
-
*
|
|
2003
|
-
* strategyName: "my-strategy",
|
|
2004
|
-
* exchangeName: "my-exchange"
|
|
3663
|
+
* // Run walker silently, only callbacks will fire
|
|
3664
|
+
* await Walker.background("BTCUSDT", {
|
|
3665
|
+
* walkerName: "my-walker"
|
|
2005
3666
|
* });
|
|
3667
|
+
* console.log("Walker comparison completed");
|
|
2006
3668
|
* ```
|
|
2007
3669
|
*/
|
|
2008
3670
|
background: (symbol: string, context: {
|
|
2009
|
-
|
|
2010
|
-
exchangeName: string;
|
|
3671
|
+
walkerName: string;
|
|
2011
3672
|
}) => () => void;
|
|
2012
3673
|
/**
|
|
2013
|
-
* Gets
|
|
3674
|
+
* Gets walker results data from all strategy comparisons.
|
|
2014
3675
|
*
|
|
2015
|
-
* @param
|
|
2016
|
-
* @
|
|
3676
|
+
* @param symbol - Trading symbol
|
|
3677
|
+
* @param walkerName - Walker name to get data for
|
|
3678
|
+
* @returns Promise resolving to walker results data object
|
|
2017
3679
|
*
|
|
2018
3680
|
* @example
|
|
2019
3681
|
* ```typescript
|
|
2020
|
-
* const
|
|
2021
|
-
* console.log(
|
|
3682
|
+
* const results = await Walker.getData("BTCUSDT", "my-walker");
|
|
3683
|
+
* console.log(results.bestStrategy, results.bestMetric);
|
|
2022
3684
|
* ```
|
|
2023
3685
|
*/
|
|
2024
|
-
getData: (
|
|
3686
|
+
getData: (symbol: string, walkerName: WalkerName) => Promise<IWalkerResults>;
|
|
2025
3687
|
/**
|
|
2026
|
-
* Generates markdown report with all
|
|
3688
|
+
* Generates markdown report with all strategy comparisons for a walker.
|
|
2027
3689
|
*
|
|
2028
|
-
* @param
|
|
3690
|
+
* @param symbol - Trading symbol
|
|
3691
|
+
* @param walkerName - Walker name to generate report for
|
|
2029
3692
|
* @returns Promise resolving to markdown formatted report string
|
|
2030
3693
|
*
|
|
2031
3694
|
* @example
|
|
2032
3695
|
* ```typescript
|
|
2033
|
-
* const markdown = await
|
|
3696
|
+
* const markdown = await Walker.getReport("BTCUSDT", "my-walker");
|
|
2034
3697
|
* console.log(markdown);
|
|
2035
3698
|
* ```
|
|
2036
3699
|
*/
|
|
2037
|
-
getReport: (
|
|
3700
|
+
getReport: (symbol: string, walkerName: WalkerName) => Promise<string>;
|
|
2038
3701
|
/**
|
|
2039
|
-
* Saves
|
|
3702
|
+
* Saves walker report to disk.
|
|
2040
3703
|
*
|
|
2041
|
-
* @param
|
|
2042
|
-
* @param
|
|
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")
|
|
2043
3707
|
*
|
|
2044
3708
|
* @example
|
|
2045
3709
|
* ```typescript
|
|
2046
|
-
* // Save to default path: ./logs/
|
|
2047
|
-
* await
|
|
3710
|
+
* // Save to default path: ./logs/walker/my-walker.md
|
|
3711
|
+
* await Walker.dump("BTCUSDT", "my-walker");
|
|
2048
3712
|
*
|
|
2049
|
-
* // Save to custom path: ./custom/path/my-
|
|
2050
|
-
* await
|
|
3713
|
+
* // Save to custom path: ./custom/path/my-walker.md
|
|
3714
|
+
* await Walker.dump("BTCUSDT", "my-walker", "./custom/path");
|
|
2051
3715
|
* ```
|
|
2052
3716
|
*/
|
|
2053
|
-
dump: (
|
|
3717
|
+
dump: (symbol: string, walkerName: WalkerName, path?: string) => Promise<void>;
|
|
2054
3718
|
}
|
|
2055
3719
|
/**
|
|
2056
|
-
* Singleton instance of
|
|
3720
|
+
* Singleton instance of WalkerUtils for convenient walker operations.
|
|
2057
3721
|
*
|
|
2058
3722
|
* @example
|
|
2059
3723
|
* ```typescript
|
|
2060
|
-
* import {
|
|
3724
|
+
* import { Walker } from "./classes/Walker";
|
|
2061
3725
|
*
|
|
2062
|
-
* for await (const result of
|
|
2063
|
-
*
|
|
2064
|
-
* exchangeName: "my-exchange",
|
|
3726
|
+
* for await (const result of Walker.run("BTCUSDT", {
|
|
3727
|
+
* walkerName: "my-walker"
|
|
2065
3728
|
* })) {
|
|
2066
|
-
* console.log("
|
|
3729
|
+
* console.log("Progress:", result.strategiesTested, "/", result.totalStrategies);
|
|
3730
|
+
* console.log("Best so far:", result.bestStrategy, result.bestMetric);
|
|
2067
3731
|
* }
|
|
2068
3732
|
* ```
|
|
2069
3733
|
*/
|
|
2070
|
-
declare const
|
|
3734
|
+
declare const Walker: WalkerUtils;
|
|
3735
|
+
|
|
3736
|
+
/**
|
|
3737
|
+
* Utility class for portfolio heatmap operations.
|
|
3738
|
+
*
|
|
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.
|
|
3742
|
+
*
|
|
3743
|
+
* @example
|
|
3744
|
+
* ```typescript
|
|
3745
|
+
* import { Heat } from "backtest-kit";
|
|
3746
|
+
*
|
|
3747
|
+
* // Get raw heatmap data for a strategy
|
|
3748
|
+
* const stats = await Heat.getData("my-strategy");
|
|
3749
|
+
* console.log(`Portfolio PNL: ${stats.portfolioTotalPnl}%`);
|
|
3750
|
+
*
|
|
3751
|
+
* // Generate markdown report
|
|
3752
|
+
* const markdown = await Heat.getReport("my-strategy");
|
|
3753
|
+
* console.log(markdown);
|
|
3754
|
+
*
|
|
3755
|
+
* // Save to disk
|
|
3756
|
+
* await Heat.dump("my-strategy", "./reports");
|
|
3757
|
+
* ```
|
|
3758
|
+
*/
|
|
3759
|
+
declare class HeatUtils {
|
|
3760
|
+
/**
|
|
3761
|
+
* Gets aggregated portfolio heatmap statistics for a strategy.
|
|
3762
|
+
*
|
|
3763
|
+
* Returns per-symbol breakdown and portfolio-wide metrics.
|
|
3764
|
+
* Data is automatically collected from all closed signals for the strategy.
|
|
3765
|
+
*
|
|
3766
|
+
* @param strategyName - Strategy name to get heatmap data for
|
|
3767
|
+
* @returns Promise resolving to heatmap statistics object
|
|
3768
|
+
*
|
|
3769
|
+
* @example
|
|
3770
|
+
* ```typescript
|
|
3771
|
+
* const stats = await Heat.getData("my-strategy");
|
|
3772
|
+
*
|
|
3773
|
+
* console.log(`Total symbols: ${stats.totalSymbols}`);
|
|
3774
|
+
* console.log(`Portfolio Total PNL: ${stats.portfolioTotalPnl}%`);
|
|
3775
|
+
* console.log(`Portfolio Sharpe Ratio: ${stats.portfolioSharpeRatio}`);
|
|
3776
|
+
*
|
|
3777
|
+
* // Iterate through per-symbol statistics
|
|
3778
|
+
* stats.symbols.forEach(row => {
|
|
3779
|
+
* console.log(`${row.symbol}: ${row.totalPnl}% (${row.totalTrades} trades)`);
|
|
3780
|
+
* });
|
|
3781
|
+
* ```
|
|
3782
|
+
*/
|
|
3783
|
+
getData: (strategyName: StrategyName) => Promise<IHeatmapStatistics>;
|
|
3784
|
+
/**
|
|
3785
|
+
* Generates markdown report with portfolio heatmap table for a strategy.
|
|
3786
|
+
*
|
|
3787
|
+
* Table includes: Symbol, Total PNL, Sharpe Ratio, Max Drawdown, Trades.
|
|
3788
|
+
* Symbols are sorted by Total PNL descending.
|
|
3789
|
+
*
|
|
3790
|
+
* @param strategyName - Strategy name to generate heatmap report for
|
|
3791
|
+
* @returns Promise resolving to markdown formatted report string
|
|
3792
|
+
*
|
|
3793
|
+
* @example
|
|
3794
|
+
* ```typescript
|
|
3795
|
+
* const markdown = await Heat.getReport("my-strategy");
|
|
3796
|
+
* console.log(markdown);
|
|
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
|
+
* // ...
|
|
3807
|
+
* ```
|
|
3808
|
+
*/
|
|
3809
|
+
getReport: (strategyName: StrategyName) => Promise<string>;
|
|
3810
|
+
/**
|
|
3811
|
+
* Saves heatmap report to disk for a strategy.
|
|
3812
|
+
*
|
|
3813
|
+
* Creates directory if it doesn't exist.
|
|
3814
|
+
* Default filename: {strategyName}.md
|
|
3815
|
+
*
|
|
3816
|
+
* @param strategyName - Strategy name to save heatmap report for
|
|
3817
|
+
* @param path - Optional directory path to save report (default: "./logs/heatmap")
|
|
3818
|
+
*
|
|
3819
|
+
* @example
|
|
3820
|
+
* ```typescript
|
|
3821
|
+
* // Save to default path: ./logs/heatmap/my-strategy.md
|
|
3822
|
+
* await Heat.dump("my-strategy");
|
|
3823
|
+
*
|
|
3824
|
+
* // Save to custom path: ./reports/my-strategy.md
|
|
3825
|
+
* await Heat.dump("my-strategy", "./reports");
|
|
3826
|
+
* ```
|
|
3827
|
+
*/
|
|
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 {
|
|
3897
|
+
/**
|
|
3898
|
+
* Calculates position size using fixed percentage risk method.
|
|
3899
|
+
*
|
|
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.
|
|
3913
|
+
*
|
|
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.
|
|
3928
|
+
*
|
|
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"
|
|
3936
|
+
*/
|
|
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 };
|
|
4018
|
+
}
|
|
2071
4019
|
|
|
2072
4020
|
/**
|
|
2073
4021
|
* Logger service with automatic context injection.
|
|
@@ -2314,6 +4262,7 @@ declare class StrategyConnectionService implements IStrategy {
|
|
|
2314
4262
|
private readonly loggerService;
|
|
2315
4263
|
private readonly executionContextService;
|
|
2316
4264
|
private readonly strategySchemaService;
|
|
4265
|
+
private readonly riskConnectionService;
|
|
2317
4266
|
private readonly exchangeConnectionService;
|
|
2318
4267
|
private readonly methodContextService;
|
|
2319
4268
|
/**
|
|
@@ -2346,97 +4295,327 @@ declare class StrategyConnectionService implements IStrategy {
|
|
|
2346
4295
|
*/
|
|
2347
4296
|
backtest: (candles: ICandleData[]) => Promise<IStrategyBacktestResult>;
|
|
2348
4297
|
/**
|
|
2349
|
-
* 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.
|
|
2350
4449
|
*
|
|
2351
|
-
*
|
|
2352
|
-
*
|
|
4450
|
+
* Creates ClientSizing on first call, returns cached instance on subsequent calls.
|
|
4451
|
+
* Cache key is sizingName string.
|
|
2353
4452
|
*
|
|
2354
|
-
* @param
|
|
2355
|
-
* @returns
|
|
4453
|
+
* @param sizingName - Name of registered sizing schema
|
|
4454
|
+
* @returns Configured ClientSizing instance
|
|
2356
4455
|
*/
|
|
2357
|
-
|
|
4456
|
+
getSizing: ((sizingName: SizingName) => ClientSizing) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, ClientSizing>;
|
|
2358
4457
|
/**
|
|
2359
|
-
*
|
|
4458
|
+
* Calculates position size based on risk parameters and configured method.
|
|
2360
4459
|
*
|
|
2361
|
-
*
|
|
2362
|
-
*
|
|
4460
|
+
* Routes to appropriate ClientSizing instance based on provided context.
|
|
4461
|
+
* Supports multiple sizing methods: fixed-percentage, kelly-criterion, atr-based.
|
|
2363
4462
|
*
|
|
2364
|
-
* @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
|
|
2365
4466
|
*/
|
|
2366
|
-
|
|
4467
|
+
calculate: (params: ISizingCalculateParams, context: {
|
|
4468
|
+
sizingName: SizingName;
|
|
4469
|
+
}) => Promise<number>;
|
|
2367
4470
|
}
|
|
2368
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;
|
|
2369
4476
|
/**
|
|
2370
|
-
*
|
|
4477
|
+
* ClientRisk implementation for portfolio-level risk management.
|
|
2371
4478
|
*
|
|
2372
|
-
*
|
|
2373
|
-
* -
|
|
2374
|
-
* -
|
|
2375
|
-
* - Configurable interval spacing (1m to 3d)
|
|
2376
|
-
* - 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
|
|
2377
4482
|
*
|
|
2378
|
-
*
|
|
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.
|
|
2379
4487
|
*/
|
|
2380
|
-
declare class
|
|
2381
|
-
readonly params:
|
|
2382
|
-
constructor(params: IFrameParams);
|
|
4488
|
+
declare class ClientRisk implements IRisk {
|
|
4489
|
+
readonly params: IRiskParams;
|
|
2383
4490
|
/**
|
|
2384
|
-
*
|
|
2385
|
-
*
|
|
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.
|
|
2386
4525
|
*
|
|
2387
|
-
*
|
|
2388
|
-
*
|
|
2389
|
-
*
|
|
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
|
|
2390
4535
|
*/
|
|
2391
|
-
|
|
4536
|
+
checkSignal: (params: IRiskCheckArgs) => Promise<boolean>;
|
|
2392
4537
|
}
|
|
2393
4538
|
|
|
2394
4539
|
/**
|
|
2395
|
-
* Connection service routing
|
|
4540
|
+
* Connection service routing risk operations to correct ClientRisk instance.
|
|
2396
4541
|
*
|
|
2397
|
-
* Routes
|
|
2398
|
-
* based on
|
|
2399
|
-
*
|
|
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.
|
|
2400
4545
|
*
|
|
2401
4546
|
* Key features:
|
|
2402
|
-
* -
|
|
2403
|
-
* - Memoized
|
|
2404
|
-
* -
|
|
2405
|
-
* - 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
|
|
2406
4550
|
*
|
|
2407
|
-
* Note:
|
|
4551
|
+
* Note: riskName is empty string for strategies without risk configuration.
|
|
2408
4552
|
*
|
|
2409
4553
|
* @example
|
|
2410
4554
|
* ```typescript
|
|
2411
4555
|
* // Used internally by framework
|
|
2412
|
-
* const
|
|
2413
|
-
*
|
|
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
|
+
* );
|
|
2414
4569
|
* ```
|
|
2415
4570
|
*/
|
|
2416
|
-
declare class
|
|
4571
|
+
declare class RiskConnectionService {
|
|
2417
4572
|
private readonly loggerService;
|
|
2418
|
-
private readonly
|
|
2419
|
-
private readonly methodContextService;
|
|
4573
|
+
private readonly riskSchemaService;
|
|
2420
4574
|
/**
|
|
2421
|
-
* Retrieves memoized
|
|
4575
|
+
* Retrieves memoized ClientRisk instance for given risk name.
|
|
2422
4576
|
*
|
|
2423
|
-
* Creates
|
|
2424
|
-
* Cache key is
|
|
4577
|
+
* Creates ClientRisk on first call, returns cached instance on subsequent calls.
|
|
4578
|
+
* Cache key is riskName string.
|
|
2425
4579
|
*
|
|
2426
|
-
* @param
|
|
2427
|
-
* @returns Configured
|
|
4580
|
+
* @param riskName - Name of registered risk schema
|
|
4581
|
+
* @returns Configured ClientRisk instance
|
|
2428
4582
|
*/
|
|
2429
|
-
|
|
4583
|
+
getRisk: ((riskName: RiskName) => ClientRisk) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, ClientRisk>;
|
|
2430
4584
|
/**
|
|
2431
|
-
*
|
|
4585
|
+
* Checks if a signal should be allowed based on risk limits.
|
|
2432
4586
|
*
|
|
2433
|
-
*
|
|
2434
|
-
*
|
|
4587
|
+
* Routes to appropriate ClientRisk instance based on provided context.
|
|
4588
|
+
* Validates portfolio drawdown, symbol exposure, position count, and daily loss limits.
|
|
2435
4589
|
*
|
|
2436
|
-
* @param
|
|
2437
|
-
* @
|
|
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
|
|
2438
4593
|
*/
|
|
2439
|
-
|
|
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>;
|
|
2440
4619
|
}
|
|
2441
4620
|
|
|
2442
4621
|
/**
|
|
@@ -2578,6 +4757,90 @@ declare class FrameGlobalService {
|
|
|
2578
4757
|
getTimeframe: (symbol: string) => Promise<Date[]>;
|
|
2579
4758
|
}
|
|
2580
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
|
+
|
|
2581
4844
|
/**
|
|
2582
4845
|
* Service for managing exchange schema registry.
|
|
2583
4846
|
*
|
|
@@ -2618,109 +4881,252 @@ declare class ExchangeSchemaService {
|
|
|
2618
4881
|
*/
|
|
2619
4882
|
override: (key: ExchangeName, value: Partial<IExchangeSchema>) => IExchangeSchema;
|
|
2620
4883
|
/**
|
|
2621
|
-
* 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.
|
|
2622
5028
|
*
|
|
2623
|
-
* @param key -
|
|
2624
|
-
* @returns
|
|
2625
|
-
* @throws Error if
|
|
5029
|
+
* @param key - Sizing name
|
|
5030
|
+
* @returns Sizing schema configuration
|
|
5031
|
+
* @throws Error if sizing name doesn't exist
|
|
2626
5032
|
*/
|
|
2627
|
-
get
|
|
5033
|
+
get(key: SizingName): ISizingSchema;
|
|
2628
5034
|
}
|
|
2629
5035
|
|
|
2630
5036
|
/**
|
|
2631
|
-
* Service for managing
|
|
5037
|
+
* Service for managing risk schema registry.
|
|
2632
5038
|
*
|
|
2633
5039
|
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
2634
|
-
*
|
|
5040
|
+
* Risk profiles are registered via addRisk() and retrieved by name.
|
|
2635
5041
|
*/
|
|
2636
|
-
declare class
|
|
5042
|
+
declare class RiskSchemaService {
|
|
2637
5043
|
readonly loggerService: LoggerService;
|
|
2638
5044
|
private _registry;
|
|
2639
5045
|
/**
|
|
2640
|
-
* Registers a new
|
|
5046
|
+
* Registers a new risk schema.
|
|
2641
5047
|
*
|
|
2642
|
-
* @param key - Unique
|
|
2643
|
-
* @param value -
|
|
2644
|
-
* @throws Error if
|
|
5048
|
+
* @param key - Unique risk profile name
|
|
5049
|
+
* @param value - Risk schema configuration
|
|
5050
|
+
* @throws Error if risk name already exists
|
|
2645
5051
|
*/
|
|
2646
|
-
register: (key:
|
|
5052
|
+
register: (key: RiskName, value: IRiskSchema) => void;
|
|
2647
5053
|
/**
|
|
2648
|
-
* Validates
|
|
5054
|
+
* Validates risk schema structure for required properties.
|
|
2649
5055
|
*
|
|
2650
5056
|
* Performs shallow validation to ensure all required properties exist
|
|
2651
5057
|
* and have correct types before registration in the registry.
|
|
2652
5058
|
*
|
|
2653
|
-
* @param
|
|
2654
|
-
* @throws Error if
|
|
2655
|
-
* @throws Error if interval is missing or not a valid SignalInterval
|
|
2656
|
-
* @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
|
|
2657
5061
|
*/
|
|
2658
5062
|
private validateShallow;
|
|
2659
5063
|
/**
|
|
2660
|
-
* Overrides an existing
|
|
5064
|
+
* Overrides an existing risk schema with partial updates.
|
|
2661
5065
|
*
|
|
2662
|
-
* @param key -
|
|
5066
|
+
* @param key - Risk name to override
|
|
2663
5067
|
* @param value - Partial schema updates
|
|
2664
|
-
* @returns Updated
|
|
2665
|
-
* @throws Error if
|
|
5068
|
+
* @returns Updated risk schema
|
|
5069
|
+
* @throws Error if risk name doesn't exist
|
|
2666
5070
|
*/
|
|
2667
|
-
override: (key:
|
|
5071
|
+
override: (key: RiskName, value: Partial<IRiskSchema>) => IRiskSchema;
|
|
2668
5072
|
/**
|
|
2669
|
-
* Retrieves a
|
|
5073
|
+
* Retrieves a risk schema by name.
|
|
2670
5074
|
*
|
|
2671
|
-
* @param key -
|
|
2672
|
-
* @returns
|
|
2673
|
-
* @throws Error if
|
|
5075
|
+
* @param key - Risk name
|
|
5076
|
+
* @returns Risk schema configuration
|
|
5077
|
+
* @throws Error if risk name doesn't exist
|
|
2674
5078
|
*/
|
|
2675
|
-
get: (key:
|
|
5079
|
+
get: (key: RiskName) => IRiskSchema;
|
|
2676
5080
|
}
|
|
2677
5081
|
|
|
2678
5082
|
/**
|
|
2679
|
-
* Service for managing
|
|
5083
|
+
* Service for managing walker schema registry.
|
|
2680
5084
|
*
|
|
2681
5085
|
* Uses ToolRegistry from functools-kit for type-safe schema storage.
|
|
2682
|
-
*
|
|
5086
|
+
* Walkers are registered via addWalker() and retrieved by name.
|
|
2683
5087
|
*/
|
|
2684
|
-
declare class
|
|
5088
|
+
declare class WalkerSchemaService {
|
|
2685
5089
|
readonly loggerService: LoggerService;
|
|
2686
5090
|
private _registry;
|
|
2687
5091
|
/**
|
|
2688
|
-
* Registers a new
|
|
5092
|
+
* Registers a new walker schema.
|
|
2689
5093
|
*
|
|
2690
|
-
* @param key - Unique
|
|
2691
|
-
* @param value -
|
|
2692
|
-
* @throws Error if
|
|
5094
|
+
* @param key - Unique walker name
|
|
5095
|
+
* @param value - Walker schema configuration
|
|
5096
|
+
* @throws Error if walker name already exists
|
|
2693
5097
|
*/
|
|
2694
|
-
register(key:
|
|
5098
|
+
register: (key: WalkerName, value: IWalkerSchema) => void;
|
|
2695
5099
|
/**
|
|
2696
|
-
* Validates
|
|
5100
|
+
* Validates walker schema structure for required properties.
|
|
2697
5101
|
*
|
|
2698
5102
|
* Performs shallow validation to ensure all required properties exist
|
|
2699
5103
|
* and have correct types before registration in the registry.
|
|
2700
5104
|
*
|
|
2701
|
-
* @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
|
|
2702
5108
|
* @throws Error if frameName is missing or not a string
|
|
2703
|
-
* @throws Error if
|
|
2704
|
-
* @throws Error if
|
|
2705
|
-
* @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
|
|
2706
5111
|
*/
|
|
2707
5112
|
private validateShallow;
|
|
2708
5113
|
/**
|
|
2709
|
-
* Overrides an existing
|
|
5114
|
+
* Overrides an existing walker schema with partial updates.
|
|
2710
5115
|
*
|
|
2711
|
-
* @param key -
|
|
5116
|
+
* @param key - Walker name to override
|
|
2712
5117
|
* @param value - Partial schema updates
|
|
2713
|
-
* @
|
|
5118
|
+
* @returns Updated walker schema
|
|
5119
|
+
* @throws Error if walker name doesn't exist
|
|
2714
5120
|
*/
|
|
2715
|
-
override(key:
|
|
5121
|
+
override: (key: WalkerName, value: Partial<IWalkerSchema>) => IWalkerSchema;
|
|
2716
5122
|
/**
|
|
2717
|
-
* Retrieves a
|
|
5123
|
+
* Retrieves a walker schema by name.
|
|
2718
5124
|
*
|
|
2719
|
-
* @param key -
|
|
2720
|
-
* @returns
|
|
2721
|
-
* @throws Error if
|
|
5125
|
+
* @param key - Walker name
|
|
5126
|
+
* @returns Walker schema configuration
|
|
5127
|
+
* @throws Error if walker name doesn't exist
|
|
2722
5128
|
*/
|
|
2723
|
-
get(key:
|
|
5129
|
+
get: (key: WalkerName) => IWalkerSchema;
|
|
2724
5130
|
}
|
|
2725
5131
|
|
|
2726
5132
|
/**
|
|
@@ -2778,6 +5184,7 @@ declare class BacktestLogicPrivateService {
|
|
|
2778
5184
|
declare class LiveLogicPrivateService {
|
|
2779
5185
|
private readonly loggerService;
|
|
2780
5186
|
private readonly strategyGlobalService;
|
|
5187
|
+
private readonly methodContextService;
|
|
2781
5188
|
/**
|
|
2782
5189
|
* Runs live trading for a symbol, streaming results as async generator.
|
|
2783
5190
|
*
|
|
@@ -2803,6 +5210,56 @@ declare class LiveLogicPrivateService {
|
|
|
2803
5210
|
run(symbol: string): AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed, void, unknown>;
|
|
2804
5211
|
}
|
|
2805
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
|
+
|
|
2806
5263
|
/**
|
|
2807
5264
|
* Public service for backtest orchestration with context management.
|
|
2808
5265
|
*
|
|
@@ -2898,6 +5355,46 @@ declare class LiveLogicPublicService {
|
|
|
2898
5355
|
}) => AsyncGenerator<IStrategyTickResultOpened | IStrategyTickResultClosed, void, unknown>;
|
|
2899
5356
|
}
|
|
2900
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
|
+
|
|
2901
5398
|
/**
|
|
2902
5399
|
* Global service providing access to live trading functionality.
|
|
2903
5400
|
*
|
|
@@ -2950,6 +5447,147 @@ declare class BacktestGlobalService {
|
|
|
2950
5447
|
}) => AsyncGenerator<IStrategyTickResultClosed, void, unknown>;
|
|
2951
5448
|
}
|
|
2952
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
|
+
|
|
2953
5591
|
/**
|
|
2954
5592
|
* @class ExchangeValidationService
|
|
2955
5593
|
* Service for managing and validating exchange configurations
|
|
@@ -2998,6 +5636,12 @@ declare class StrategyValidationService {
|
|
|
2998
5636
|
* Injected logger service instance
|
|
2999
5637
|
*/
|
|
3000
5638
|
private readonly loggerService;
|
|
5639
|
+
/**
|
|
5640
|
+
* @private
|
|
5641
|
+
* @readonly
|
|
5642
|
+
* Injected risk validation service instance
|
|
5643
|
+
*/
|
|
5644
|
+
private readonly riskValidationService;
|
|
3001
5645
|
/**
|
|
3002
5646
|
* @private
|
|
3003
5647
|
* Map storing strategy schemas by strategy name
|
|
@@ -3010,9 +5654,10 @@ declare class StrategyValidationService {
|
|
|
3010
5654
|
*/
|
|
3011
5655
|
addStrategy: (strategyName: StrategyName, strategySchema: IStrategySchema) => void;
|
|
3012
5656
|
/**
|
|
3013
|
-
* Validates the existence of a strategy
|
|
5657
|
+
* Validates the existence of a strategy and its risk profile (if configured)
|
|
3014
5658
|
* @public
|
|
3015
5659
|
* @throws {Error} If strategyName is not found
|
|
5660
|
+
* @throws {Error} If riskName is configured but not found
|
|
3016
5661
|
* Memoized function to cache validation results
|
|
3017
5662
|
*/
|
|
3018
5663
|
validate: (strategyName: StrategyName, source: string) => void;
|
|
@@ -3061,27 +5706,155 @@ declare class FrameValidationService {
|
|
|
3061
5706
|
list: () => Promise<IFrameSchema[]>;
|
|
3062
5707
|
}
|
|
3063
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
|
+
|
|
3064
5821
|
declare const backtest: {
|
|
3065
5822
|
exchangeValidationService: ExchangeValidationService;
|
|
3066
5823
|
strategyValidationService: StrategyValidationService;
|
|
3067
5824
|
frameValidationService: FrameValidationService;
|
|
5825
|
+
walkerValidationService: WalkerValidationService;
|
|
5826
|
+
sizingValidationService: SizingValidationService;
|
|
5827
|
+
riskValidationService: RiskValidationService;
|
|
3068
5828
|
backtestMarkdownService: BacktestMarkdownService;
|
|
3069
5829
|
liveMarkdownService: LiveMarkdownService;
|
|
5830
|
+
performanceMarkdownService: PerformanceMarkdownService;
|
|
5831
|
+
walkerMarkdownService: WalkerMarkdownService;
|
|
5832
|
+
heatMarkdownService: HeatMarkdownService;
|
|
3070
5833
|
backtestLogicPublicService: BacktestLogicPublicService;
|
|
3071
5834
|
liveLogicPublicService: LiveLogicPublicService;
|
|
5835
|
+
walkerLogicPublicService: WalkerLogicPublicService;
|
|
3072
5836
|
backtestLogicPrivateService: BacktestLogicPrivateService;
|
|
3073
5837
|
liveLogicPrivateService: LiveLogicPrivateService;
|
|
5838
|
+
walkerLogicPrivateService: WalkerLogicPrivateService;
|
|
3074
5839
|
exchangeGlobalService: ExchangeGlobalService;
|
|
3075
5840
|
strategyGlobalService: StrategyGlobalService;
|
|
3076
5841
|
frameGlobalService: FrameGlobalService;
|
|
3077
5842
|
liveGlobalService: LiveGlobalService;
|
|
3078
5843
|
backtestGlobalService: BacktestGlobalService;
|
|
5844
|
+
walkerGlobalService: WalkerGlobalService;
|
|
5845
|
+
sizingGlobalService: SizingGlobalService;
|
|
5846
|
+
riskGlobalService: RiskGlobalService;
|
|
3079
5847
|
exchangeSchemaService: ExchangeSchemaService;
|
|
3080
5848
|
strategySchemaService: StrategySchemaService;
|
|
3081
5849
|
frameSchemaService: FrameSchemaService;
|
|
5850
|
+
walkerSchemaService: WalkerSchemaService;
|
|
5851
|
+
sizingSchemaService: SizingSchemaService;
|
|
5852
|
+
riskSchemaService: RiskSchemaService;
|
|
3082
5853
|
exchangeConnectionService: ExchangeConnectionService;
|
|
3083
5854
|
strategyConnectionService: StrategyConnectionService;
|
|
3084
5855
|
frameConnectionService: FrameConnectionService;
|
|
5856
|
+
sizingConnectionService: SizingConnectionService;
|
|
5857
|
+
riskConnectionService: RiskConnectionService;
|
|
3085
5858
|
executionContextService: {
|
|
3086
5859
|
readonly context: IExecutionContext;
|
|
3087
5860
|
};
|
|
@@ -3091,4 +5864,4 @@ declare const backtest: {
|
|
|
3091
5864
|
loggerService: LoggerService;
|
|
3092
5865
|
};
|
|
3093
5866
|
|
|
3094
|
-
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, 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 };
|