This document defines the IWalkerSchema interface for registering Walker components via addWalker(). Walker schemas configure strategy comparison operations that run multiple strategies sequentially and rank them by a chosen performance metric.
For information about executing Walker operations, see Walker API. For details about Walker execution flow and implementation, see Walker Mode.
Walker schemas are registered using the IWalkerSchema interface, which specifies a collection of strategies to compare, a metric for ranking, and the execution environment.
Unique identifier for the Walker configuration. Used to retrieve Walker instances via dependency injection and for logging/reporting.
walkerName: WalkerName; // string type alias
Example:
walkerName: "btc-strategy-comparison"
Array of strategy names to compare. Each strategy must be registered via addStrategy() before Walker execution. Strategies are executed sequentially in array order.
strategies: StrategyName[]; // StrategyName[] = string[]
Example:
strategies: [
"rsi-strategy",
"macd-strategy",
"bollinger-strategy"
]
Walker executes each strategy using the same exchangeName and frameName, ensuring fair comparison under identical market conditions.
Performance metric used to rank strategies and determine the best performer. The metric value is extracted from BacktestStatistics after each strategy completes.
metric: WalkerMetric;
type WalkerMetric =
| "sharpeRatio"
| "annualizedSharpeRatio"
| "winRate"
| "avgPnl"
| "totalPnl"
| "certaintyRatio"
| "expectedYearlyReturns";
Exchange configuration to use for all strategy backtests. Must be registered via addExchange() before Walker execution. All strategies in the comparison use this same exchange.
exchangeName: ExchangeName; // string type alias
Example:
exchangeName: "binance"
Frame (timeframe) configuration to use for all strategy backtests. Must be registered via addFrame() before Walker execution. All strategies are tested against this same historical period.
frameName: FrameName; // string type alias
Example:
frameName: "2024-q1"
The metric field determines how strategies are ranked. Higher metric values indicate better performance (except for negative PnL scenarios).
| Metric | Description | Formula / Source | Typical Range |
|---|---|---|---|
sharpeRatio |
Risk-adjusted returns (daily) | avgPnl / stdDevPnl |
-∞ to +∞ (>1 is good) |
annualizedSharpeRatio |
Sharpe ratio scaled to annual basis | sharpeRatio * sqrt(252) |
-∞ to +∞ (>2 is excellent) |
winRate |
Percentage of profitable trades | (winCount / totalSignals) * 100 |
0% to 100% |
avgPnl |
Average profit/loss per trade | totalPnl / totalSignals |
-∞ to +∞ |
totalPnl |
Cumulative profit/loss (all trades) | sum(pnlPercentage) |
-∞ to +∞ |
certaintyRatio |
Consistency of returns | (avgPnl * winRate) / stdDevPnl |
-∞ to +∞ |
expectedYearlyReturns |
Annualized expected return | avgPnl * tradesPerYear |
-∞ to +∞ |
Default metric: sharpeRatio is commonly used as the default metric for strategy comparison because it accounts for both returns and risk.
Metric selection guidance:
sharpeRatio or annualizedSharpeRatio for risk-adjusted comparisonwinRate if consistency is more important than magnitudetotalPnl or avgPnl for absolute return comparisoncertaintyRatio for strategies with varying volatilityexpectedYearlyReturns for long-term performance projectionHuman-readable description for documentation purposes. Not used by the system, but helpful for understanding Walker configuration intent.
note?: string;
Example:
note: "Compare momentum strategies during Q1 2024 bull market"
Lifecycle event callbacks triggered during Walker execution. Provides hooks for monitoring progress and results.
callbacks?: Partial<IWalkerCallbacks>;
Walker execution emits events at key lifecycle points via the IWalkerCallbacks interface.
Invoked after each strategy completes its backtest. Receives full backtest results and statistics for the strategy.
onStrategy: (
walkerName: WalkerName,
strategyName: StrategyName,
results: IStrategyBacktestResult[],
statistics: BacktestStatistics
) => void;
Parameters:
walkerName: Identifier of the Walker configurationstrategyName: Name of the strategy that just completedresults: Array of all closed signals from the backteststatistics: Calculated performance metrics (BacktestStatistics)Use cases:
Invoked after all strategies complete and comparative ranking is determined. Receives aggregated results with best strategy identification.
onComplete: (
walkerName: WalkerName,
results: IWalkerResults
) => void;
Parameters:
walkerName: Identifier of the Walker configurationresults: Complete Walker results including rankingUse cases:
Walker execution produces IWalkerResults containing the best strategy, its metric value, and full statistics for all strategies.
interface IWalkerResults {
/** Name of the highest-performing strategy */
bestStrategy: StrategyName;
/** Metric value of the best strategy */
bestMetric: number;
/** Complete results for all strategies (ordered by execution) */
strategies: IWalkerStrategyResult[];
}
interface IWalkerStrategyResult {
/** Strategy identifier */
strategyName: StrategyName;
/** Full performance statistics from backtest */
statistics: BacktestStatistics;
}
Best strategy selection: The strategy with the highest value for the specified metric is chosen. All metrics are maximization targets (higher is better).
Result ordering: The strategies array maintains the execution order (same as input strategies array), not sorted by performance. To find ranking, compare statistics[metric] values.
Accessing results:
// Via Walker.getData()
const results = await Walker.getData("btc-strategy-comparison");
console.log(`Best: ${results.bestStrategy} (${results.bestMetric})`);
// Via listenWalkerComplete()
listenWalkerComplete((walkerName, results) => {
const winner = results.strategies.find(
s => s.strategyName === results.bestStrategy
);
console.log(winner.statistics);
});
Walker schemas are registered using the addWalker() function, which validates the configuration and stores it in the WalkerSchemaService registry.
Basic registration:
import { addWalker } from 'backtest-kit';
await addWalker({
walkerName: "momentum-comparison",
strategies: ["rsi-strategy", "macd-strategy"],
metric: "sharpeRatio",
exchangeName: "binance",
frameName: "2024-q1"
});
With callbacks:
await addWalker({
walkerName: "momentum-comparison",
note: "Compare RSI vs MACD during bull market",
strategies: ["rsi-strategy", "macd-strategy"],
metric: "annualizedSharpeRatio",
exchangeName: "binance",
frameName: "2024-q1",
callbacks: {
onStrategy: (walkerName, strategyName, results, stats) => {
console.log(`${strategyName}: Sharpe = ${stats.sharpeRatio}`);
},
onComplete: (walkerName, results) => {
console.log(`Winner: ${results.bestStrategy}`);
}
}
});
Walker schemas undergo validation before registration to ensure configuration integrity.
| Validation | Rule | Error Example |
|---|---|---|
| walkerName uniqueness | Must not already be registered | Walker "test" already exists |
| walkerName presence | Must be non-empty string | walkerName is required |
| strategies presence | Array must not be empty | strategies array cannot be empty |
| strategies existence | All strategies must be registered | Strategy "unknown" not found |
| metric validity | Must be valid WalkerMetric value | Invalid metric "invalid" |
| exchangeName existence | Exchange must be registered | Exchange "unknown" not found |
| frameName existence | Frame must be registered | Frame "unknown" not found |
Validation timing: All validation occurs synchronously during addWalker() call, before the schema is stored. Registration either succeeds completely or throws an error.
Validation implementation: src/lib/services/validation/WalkerValidationService.ts
The strategies array order determines execution sequence, which affects:
progressWalkerEmitter emits after each strategy completes, showing index-based progressonStrategy fires in array orderExecution diagram:
Best practice: Place high-priority or baseline strategies first in the array for earlier feedback during long-running comparisons.
Walker schemas are consumed by the Walker execution pipeline during Walker.run() or Walker.background() operations.
Execution flow:
Walker.run(walkerName)WalkerCommandService validates Walker existsWalkerLogicPrivateService retrieves schema from WalkerSchemaServiceBacktestLogicPublicServiceBacktestStatisticsonStrategy callbackIWalkerResults and fire onComplete callbackWalker.getData()import { addStrategy, addExchange, addFrame, addWalker } from 'backtest-kit';
// Register dependencies
await addExchange({
exchangeName: "binance",
getCandles: async (symbol, interval, since, limit) => {
// CCXT implementation
},
formatPrice: async (symbol, price) => price.toFixed(2),
formatQuantity: async (symbol, qty) => qty.toFixed(8)
});
await addFrame({
frameName: "2024-q1",
interval: "1h",
startDate: new Date("2024-01-01"),
endDate: new Date("2024-03-31")
});
await addStrategy({
strategyName: "rsi-oversold",
interval: "1h",
getSignal: async (symbol, when) => {
// RSI calculation and signal logic
return { position: "long", priceTakeProfit: 50000, priceStopLoss: 48000, minuteEstimatedTime: 1440 };
}
});
await addStrategy({
strategyName: "macd-crossover",
interval: "1h",
getSignal: async (symbol, when) => {
// MACD calculation and signal logic
return { position: "long", priceTakeProfit: 51000, priceStopLoss: 47000, minuteEstimatedTime: 2880 };
}
});
// Register Walker
await addWalker({
walkerName: "momentum-strategies",
note: "Compare RSI vs MACD momentum strategies in Q1 2024",
strategies: [
"rsi-oversold",
"macd-crossover"
],
metric: "annualizedSharpeRatio",
exchangeName: "binance",
frameName: "2024-q1",
callbacks: {
onStrategy: (walkerName, strategyName, results, statistics) => {
console.log(`Completed ${strategyName}:`);
console.log(` Signals: ${statistics.totalSignals}`);
console.log(` Win Rate: ${statistics.winRate}%`);
console.log(` Sharpe: ${statistics.sharpeRatio}`);
},
onComplete: (walkerName, results) => {
console.log(`\nBest strategy: ${results.bestStrategy}`);
console.log(`Best metric: ${results.bestMetric.toFixed(2)}`);
// Generate comparison table
results.strategies.forEach(s => {
console.log(`${s.strategyName}: ${s.statistics.annualizedSharpeRatio}`);
});
}
}
});
// Execute Walker
import { Walker } from 'backtest-kit';
for await (const progress of Walker.run("BTCUSDT", {
walkerName: "momentum-strategies"
})) {
console.log(`Progress: ${progress.completed}/${progress.total}`);
}
// Access results
const results = await Walker.getData("momentum-strategies");
console.log(`Winner: ${results.bestStrategy}`);