Торговый бот — чёрный ящик, пока у вас нет дашборда. Вы видите только конечный PnL, но не знаете, как стратегия ведёт себя внутри дня. Просадка в 35% может остаться незамеченной, если смотреть только на win rate. Дашборд статистики криптобота даёт прозрачность: equity curve, drawdown, реальный Sharpe ratio. Без этого вы рискуете потерять депозит. Наши дашборды строятся на real-time WebSocket и REST API, обновляются каждые 5 секунд. Результат — мгновенная реакция на изменения рынка и своевременная остановка убыточных стратегий.
Проблемы, которые решает дашборд
Первая проблема — скрытые просадки. Бот может показывать 70% win rate, но редкие крупные потери съедают всю прибыль. Equity curve визуализирует реальное состояние депозита. Вторая — отсутствие контекста. Без метрик риска (Sharpe, drawdown) невозможно сравнить две стратегии объективно. Третья — задержки в мониторинге. REST polling раз в минуту пропускает важные сигналы: проскальзывание (slippage) или атаки MEV на DEX. Real-time WebSocket решает это.
Почему equity curve — главный график криптобота?
Win rate 80% может скрывать редкие крупные потери. Equity curve показывает реальную динамику капитала. Хорошая кривая — плавный рост с контролируемыми просадками. Плохая — резкие падения на 30-40%, после которых бот не восстанавливается. Именно equity curve позволяет увидеть true drawdown, который не виден в сводных метриках. Дополнительно строим кривую с учётом slippage и комиссий — это даёт честную картину.
Какие метрики обязательны в дашборде?
Мы выделяем пять ключевых:
- Profit factor — отношение прибыльных сделок к убыточным. Значение >2 означает $2 прибыли на каждый $1 риска.
- Sharpe ratio — доходность с поправкой на риск. Чем выше, тем стабильнее стратегия.
- Max drawdown — максимальная просадка от пика до дна. Позволяет оценить риск депозита.
- Average trade duration — среднее время удержания позиции. Важно для high-frequency стратегий.
- Consecutive losses — серия убыточных сделок. Выявляет периоды нестабильности.
Эти метрики помогают вовремя заметить, что бот начинает деградировать — например, растёт max drawdown или падает profit factor. Закажите консультацию инженера, чтобы подобрать оптимальный набор под вашу стратегию.
Реализация на Python с Decimal
Для точного расчёта метрик используем Decimal. Ниже — ключевые методы из нашего класса PerformanceCalculator:
from decimal import Decimal
from typing import List
import statistics
import math
class PerformanceCalculator:
def __init__(self, trades: list[ClosedTrade], initial_capital: Decimal):
self.trades = sorted(trades, key=lambda t: t.closed_at)
self.initial_capital = initial_capital
def total_pnl(self) -> Decimal:
return sum(t.pnl for t in self.trades)
def total_roi(self) -> float:
return float(self.total_pnl() / self.initial_capital * 100)
def win_rate(self) -> float:
if not self.trades:
return 0
wins = sum(1 for t in self.trades if t.pnl > 0)
return wins / len(self.trades) * 100
def profit_factor(self) -> float:
gross_profit = sum(float(t.pnl) for t in self.trades if t.pnl > 0)
gross_loss = abs(sum(float(t.pnl) for t in self.trades if t.pnl < 0))
return gross_profit / gross_loss if gross_loss > 0 else float('inf')
def max_drawdown(self) -> float:
equity = float(self.initial_capital)
peak = equity
max_dd = 0
for trade in self.trades:
equity += float(trade.pnl)
if equity > peak:
peak = equity
dd = (peak - equity) / peak
max_dd = max(max_dd, dd)
return max_dd * 100
def sharpe_ratio(self, risk_free_rate: float = 0.05) -> float:
if len(self.trades) < 2:
return 0
daily_returns = self.build_daily_returns()
if not daily_returns:
return 0
avg_daily_return = statistics.mean(daily_returns)
std_daily_return = statistics.stdev(daily_returns)
if std_daily_return == 0:
return 0
daily_rf = risk_free_rate / 365
sharpe = (avg_daily_return - daily_rf) / std_daily_return * math.sqrt(365)
return round(sharpe, 2)
def avg_trade_duration_hours(self) -> float:
if not self.trades:
return 0
durations = [(t.closed_at - t.opened_at).total_seconds() / 3600 for t in self.trades]
return statistics.mean(durations)
def consecutive_losses(self) -> int:
max_streak = 0
current_streak = 0
for trade in self.trades:
if trade.pnl < 0:
current_streak += 1
max_streak = max(max_streak, current_streak)
else:
current_streak = 0
return max_streak
def build_equity_curve(self) -> list[dict]:
equity = float(self.initial_capital)
curve = [{'date': self.trades[0].opened_at, 'equity': equity}]
for trade in self.trades:
equity += float(trade.pnl)
curve.append({
'date': trade.closed_at,
'equity': equity,
'pnl': float(trade.pnl),
'cumulative_roi': (equity / float(self.initial_capital) - 1) * 100
})
return curve
Backend API на FastAPI
FastAPI-эндпоинты для получения статистики и списка сделок с пагинацией.
from fastapi import FastAPI, Query
from datetime import datetime, timedelta
app = FastAPI()
@app.get("/api/bot/{bot_id}/stats")
async def get_bot_stats(bot_id: str, period: str = Query("30d", regex="^(7d|30d|90d|all)$")):
days = {'7d': 7, '30d': 30, '90d': 90, 'all': None}[period]
since = datetime.utcnow() - timedelta(days=days) if days else None
trades = await db.get_closed_trades(bot_id, since=since)
initial_capital = await db.get_initial_capital(bot_id)
open_positions = await db.get_open_positions(bot_id)
calc = PerformanceCalculator(trades, initial_capital)
return {
"period": period,
"summary": {
"total_pnl_usdt": str(calc.total_pnl()),
"total_roi_percent": round(calc.total_roi(), 2),
"win_rate_percent": round(calc.win_rate(), 1),
"profit_factor": round(calc.profit_factor(), 2),
"sharpe_ratio": calc.sharpe_ratio(),
"max_drawdown_percent": round(calc.max_drawdown(), 2),
"total_trades": len(trades),
"avg_trade_duration_hours": round(calc.avg_trade_duration_hours(), 1),
"max_consecutive_losses": calc.consecutive_losses(),
},
"equity_curve": calc.build_equity_curve(),
"open_positions": [p.to_dict() for p in open_positions],
"current_status": await get_bot_status(bot_id)
}
@app.get("/api/bot/{bot_id}/trades")
async def get_trades(bot_id: str, page: int = 1, limit: int = 50, symbol: str = None):
trades = await db.get_trades_paginated(bot_id, page, limit, symbol)
return {
"trades": [t.to_dict() for t in trades.items],
"total": trades.total,
"page": page,
"pages": math.ceil(trades.total / limit)
}
Frontend на React
Компоненты для визуализации: график equity curve и KPI-карточки.
import { LineChart, Line, XAxis, YAxis, Tooltip, ReferenceLine } from 'recharts';
const EquityCurveChart: React.FC<{data: EquityPoint[]}> = ({ data }) => {
const initialEquity = data[0]?.equity || 0;
return (
<LineChart width={800} height={300} data={data}>
<XAxis dataKey="date" tickFormatter={d => format(new Date(d), 'MM/dd')} />
<YAxis tickFormatter={v => `$${(v/1000).toFixed(1)}k`} />
<Tooltip formatter={(value: number) => [`$${value.toFixed(2)}`, 'Equity']} labelFormatter={d => format(new Date(d), 'PPpp')} />
<ReferenceLine y={initialEquity} stroke="#888" strokeDasharray="3 3" label="Start" />
<Line type="monotone" dataKey="equity" stroke={data[data.length-1]?.equity >= initialEquity ? '#22c55e' : '#ef4444'} dot={false} strokeWidth={2} />
</LineChart>
);
};
const StatCard: React.FC<{label: string; value: string; positive?: boolean}> = ({ label, value, positive }) => (
<div className="bg-white rounded-xl p-4 shadow-sm border">
<div className="text-sm text-gray-500">{label}</div>
<div className={`text-2xl font-bold mt-1 ${positive === true ? 'text-green-600' : positive === false ? 'text-red-600' : 'text-gray-900'}`}>{value}</div>
</div>
);
Real-time мониторинг через WebSocket
Обновление текущего состояния бота каждые 5 секунд.
class BotStatusWebSocket:
async def stream_status(self, websocket, bot_id: str):
while True:
status = {
"bot_running": await is_bot_running(bot_id),
"open_positions": await get_open_positions_summary(bot_id),
"today_pnl": str(await get_today_pnl(bot_id)),
"last_trade_at": await get_last_trade_time(bot_id),
"api_latency_ms": await get_avg_latency(bot_id),
"errors_last_hour": await get_error_count(bot_id, hours=1),
}
await websocket.send_json(status)
await asyncio.sleep(5)
Сравнение методов получения данных
| Характеристика | WebSocket | REST polling (каждую минуту) |
|---|---|---|
| Задержка данных | 5 секунд | 60 секунд |
| Нагрузка на сервер | Низкая (постоянное соединение) | Высокая (частые запросы) |
| Сложность реализации | Средняя | Низкая |
Наш дашборд на WebSocket обновляется в 10 раз быстрее, чем REST polling раз в минуту. Это критично для high-frequency стратегий, где каждая секунда влияет на PnL.
Этапы разработки дашборда
| Этап | Длительность | Результат |
|---|---|---|
| Консультация и сбор требований | 1-2 дня | Техническое задание |
| Прототипирование интерфейса | 3-5 дней | Макет дашборда |
| Backend (API, агрегация, WebSocket) | 5-10 дней | Рабочие эндпоинты |
| Frontend (графики, карточки, фильтры) | 5-10 дней | Интерфейс дашборда |
| Интеграция и тестирование | 3-5 дней | Приёмка, обучение |
Средний клиент после внедрения дашборда увеличивает прибыль на 15% за счёт своевременной остановки убыточных стратегий. Мы более 5 лет в блокчейне, разработали дашборды для 50+ торговых ботов. Гарантируем корректность метрик и 99.9% uptime.
Пример расчёта на реальных данных
Рассмотрим бота на Binance с депозитом $10 000. За месяц совершено 200 сделок: 120 прибыльных (средняя прибыль $50) и 80 убыточных (средний убыток $30). Profit factor = (12050)/(8030) = 6000/2400 = 2.5. Max drawdown = -8% (пик $11 200, дно $10 304). Sharpe ratio = 1.8. Такие метрики говорят о стабильной стратегии.
Что входит в работу
- Анализ ваших текущих данных и метрик.
- Проектирование API (REST + WebSocket).
- Разработка backend на Python (FastAPI, PostgreSQL, Redis).
- Frontend на React (Recharts, Tailwind).
- Интеграция real-time мониторинга.
- Документация, обучение команды, поддержка 30 дней.
Закажите разработку дашборда для вашего криптобота — получите консультацию инженера бесплатно. Свяжитесь с нами для аудита метрик вашего бота. Экономия на комиссиях и своевременное выявление проблем окупают внедрение в течение первого месяца.







