UNPKG

@gabriel3615/ta_analysis

Version:

stock ta analysis

58 lines (57 loc) 2.14 kB
import { Backtester, } from './Backtester.js'; function cartesianProduct(arrays) { return arrays.reduce((acc, arr) => { const next = []; for (const a of acc) { for (const b of arr) { next.push([...a, b]); } } return next; }, [[]]); } function buildParamCombos(grid) { const keys = Object.keys(grid); if (keys.length === 0) return [{}]; const values = keys.map(k => grid[k]); const combos = cartesianProduct(values); return combos.map(vals => { const obj = {}; vals.forEach((v, idx) => (obj[keys[idx]] = v)); return obj; }); } export async function runGridSearch(candles, grid, strategyFactory, backtesterInstance // Allow passing a pre-configured backtester ) { const paramCombos = buildParamCombos(grid); const runs = []; for (const params of paramCombos) { const strategy = strategyFactory(params); const backtester = backtesterInstance ?? new Backtester(); // Use provided instance or create a default one const result = await backtester.run(candles, strategy); runs.push({ params, result }); } const bestByTotalPnL = runs.length ? runs.reduce((a, b) => (a.result.totalPnL > b.result.totalPnL ? a : b)) : null; const bestBySharpe = runs.length ? runs.reduce((a, b) => a.result.metrics.sharpe > b.result.metrics.sharpe ? a : b) : null; const bestByMaxDrawdown = runs.length ? runs.reduce((a, b) => a.result.metrics.maxDrawdown < b.result.metrics.maxDrawdown ? a : b) : null; return { runs, summary: { bestByTotalPnL, bestBySharpe, bestByMaxDrawdown } }; } export function formatMetricsPanel(run) { const m = run.result.metrics; return [ `PnL: ${run.result.totalPnL.toFixed(2)}`, `WinRate: ${(m.winRate * 100).toFixed(2)}%`, `AvgWin: ${m.avgWin.toFixed(2)}`, `AvgLoss: ${m.avgLoss.toFixed(2)}`, `MaxDD: ${(m.maxDrawdown * 100).toFixed(2)}%`, `Sharpe: ${m.sharpe.toFixed(2)}`, `Trades: ${m.tradeCount}`, ].join(' | '); }