Разработка дашборда аналитики бэктестов
Типичная проблема: стратег запускает бэктест на Python (backtrader, bt, vectorbt), получает JSON с тысячами строк OHLCV и сигналов, и отправляет это в Excel. Нормальный дашборд для бэктестов — это не «красивые графики», это инструмент для быстрого выявления проблем: overfitting, survivorship bias, неправильный slippage. Визуализация должна делать проблемы очевидными.
Ключевые метрики и их отображение
Equity curve
Основной график — equity curve с drawdown panel под ней. Не просто линия баланса, а:
- Equity line (portfolio value в USD/BTC)
- Benchmark line (buy & hold того же актива)
- Underwater plot (глубина текущей просадки в %)
Если equity curve «гладкая» относительно бенчмарка — возможный признак overfitting или look-ahead bias в данных.
Статистика стратегии
interface BacktestStats {
totalReturn: number; // %
annualizedReturn: number; // %
sharpeRatio: number; // > 1 приемлемо, > 2 хорошо
sortinoRatio: number; // только downside volatility
maxDrawdown: number; // % от пика
maxDrawdownDuration: number; // дней
winRate: number; // % прибыльных сделок
profitFactor: number; // gross profit / gross loss
avgWin: number; // средняя прибыльная сделка
avgLoss: number; // средняя убыточная сделка
totalTrades: number;
calmarRatio: number; // annualizedReturn / maxDrawdown
}
Эти метрики выносим в summary panel крупным шрифтом, с цветовой индикацией (красный/зелёный относительно пороговых значений).
Технический стек
Frontend
React + Recharts или TradingView Lightweight Charts для финансовых данных. Lightweight Charts от TradingView — специализированная библиотека с candlestick, volume, overlay indicator поддержкой из коробки. Recharts гибче для кастомных нестандартных визуализаций.
import { createChart, ColorType, LineStyle } from 'lightweight-charts';
function EquityCurve({ equityData, benchmarkData }: Props) {
const chartContainerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const chart = createChart(chartContainerRef.current!, {
width: chartContainerRef.current!.clientWidth,
height: 400,
layout: { background: { type: ColorType.Solid, color: '#1a1a2e' }, textColor: '#d1d5db' },
grid: { vertLines: { color: '#2d3748' }, horzLines: { color: '#2d3748' } },
timeScale: { timeVisible: true },
});
const equitySeries = chart.addLineSeries({ color: '#10b981', lineWidth: 2 });
const benchmarkSeries = chart.addLineSeries({ color: '#6366f1', lineWidth: 1, lineStyle: LineStyle.Dashed });
equitySeries.setData(equityData);
benchmarkSeries.setData(benchmarkData);
chart.timeScale().fitContent();
return () => chart.remove();
}, [equityData, benchmarkData]);
return <div ref={chartContainerRef} />;
}
Trades table
Таблица сделок с сортировкой и фильтрацией — TanStack Table (react-table v8). Для тысяч строк — обязательная виртуализация через @tanstack/react-virtual:
import { useVirtualizer } from '@tanstack/react-virtual';
// Рендерим только видимые строки
const rowVirtualizer = useVirtualizer({
count: trades.length,
getScrollElement: () => parentRef.current,
estimateSize: () => 40, // высота строки
overscan: 10,
});
Без виртуализации таблица на 10,000 строк вызовет freeze UI на несколько секунд при рендере.
Хранение и загрузка данных
Бэктест результаты — структурированный JSON. Для крупных бэктестов (1m данные за несколько лет = десятки MB) загружать всё сразу нецелесообразно. Схема:
interface BacktestResult {
id: string;
metadata: BacktestMetadata; // конфигурация стратегии
stats: BacktestStats; // агрегированная статистика
equityCurve: TimeseriesPoint[]; // дневные точки (обычно < 5000 штук)
trades: Trade[]; // список сделок
// OHLCV данные НЕ хранить — загружать отдельно по требованию
}
API endpoint с пагинацией для trades + отдельный endpoint для equity curve. Первый рендер — показываем stats + equity curve (легко), trades подгружаем по запросу.
Сравнение нескольких стратегий
Мощная функция — наложение equity curves нескольких бэктестов на один график. Пользователь выбирает 2-5 стратегий из списка, видит их сравнение визуально и в таблице параметров:
interface ComparisonView {
strategies: Array<{
id: string;
name: string;
color: string;
stats: BacktestStats;
equityCurve: TimeseriesPoint[];
}>;
}
Correlation matrix между стратегиями — важна для портфельного подбора. Если две стратегии высоко коррелированы, держать обе нет смысла.
Monte Carlo visualization
Monte Carlo симуляция (перемешивание порядка сделок N раз) показывает диапазон возможных исходов. Отображается как fan chart — центральная линия медианного исхода + диапазоны 10th/90th перцентиля:
// Genereate fan chart data
const percentiles = monteCarloRuns.reduce((acc, run, idx) => {
run.forEach((point, t) => {
if (!acc[t]) acc[t] = [];
acc[t].push(point.equity);
});
return acc;
}, [] as number[][]).map(values => ({
p10: percentile(values, 10),
p50: percentile(values, 50),
p90: percentile(values, 90),
}));
Ориентиры по срокам
Equity curve + stats + trades table с виртуализацией — 2 дня. Добавление сравнения стратегий + Monte Carlo fan chart + фильтрация по периодам — 3-5 дней суммарно.







