Development of a Crypto Bot Dashboard with Real-Time Analytics

A trading bot without a dashboard is a black box: you see only the final PnL, but miss hidden drawdowns and real risk. We build crypto bot statistics dashboards with real-time analytics that visualize equity curve, drawdown, and key performance metrics. Our team delivers turnkey projects—from data audit to implementation and ongoing support—ensuring transparency and reliability for your deposit.

Blockchain Development Services

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1335
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1293
  • B2B Advance company logo design
    B2B Advance company logo design
    738
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1031
  • AIDER company logo development
    AIDER company logo development
    978
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1087

Development of a Crypto Bot Dashboard with Real-Time Analytics

A trading bot is a black box until you have a dashboard. You only see the final PnL, but don't know how the strategy behaves intraday. A 35% drawdown can go unnoticed if you just look at win rate. A crypto bot statistics dashboard provides transparency: equity curve, drawdown, real Sharpe ratio. Without it, you risk losing your deposit. Our dashboards are built on real-time WebSocket and REST API, updating every 5 seconds. The result is instant reaction to market changes and timely stop of unprofitable strategies.

Problems the Dashboard Solves

The first problem is hidden drawdowns. A bot can show 70% win rate, but rare large losses eat all profit. Equity curve visualizes the real account state. Second, lack of context. Without risk metrics (Sharpe, drawdown) you cannot objectively compare two strategies. Third, monitoring delays. REST polling once a minute misses important signals: slippage or MEV attacks on DEXes. Real-time WebSocket solves this.

Why Equity Curve Is the Main Chart for a Crypto Bot?

An 80% win rate can hide rare large losses. Equity curve shows real capital dynamics. A good curve: steady growth with controlled drawdowns. A bad one: sharp 30-40% drops after which the bot never recovers. Equity curve reveals the true drawdown hidden in summary metrics. Additionally, we plot the curve accounting for slippage and fees — this gives an honest picture.

What Metrics Are Mandatory in the Dashboard?

We highlight five key ones:

  • Profit factor — ratio of profitable to losing trades. A value >2 means $2 profit for every $1 risk.
  • Sharpe ratio — risk-adjusted return. Higher means more stable strategy.
  • Max drawdown — maximum drop from peak to trough. Assesses deposit risk.
  • Average trade duration — mean holding time per position. Important for high-frequency strategies.
  • Consecutive losses — streak of losing trades. Reveals periods of instability.

These metrics help you notice early when a bot starts degrading — e.g., increasing max drawdown or falling profit factor. Contact us for an engineer consultation to choose the optimal set for your strategy.

Implementation in Python with Decimal

For precise metric calculation we use Decimal. Below are key methods from our PerformanceCalculator class:

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 with FastAPI

FastAPI endpoints for statistics and paginated trade list.

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 with React

Components for equity curve chart and KPI cards.

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 Monitoring via WebSocket

Every 5 seconds we update the current bot state.

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) 

Comparison of Data Retrieval Methods

Characteristic WebSocket REST polling (every minute)
Data latency 5 seconds 60 seconds
Server load Low (persistent connection) High (frequent requests)
Implementation complexity Medium Low

Our WebSocket dashboard updates 10 times faster than REST polling once per minute. This is critical for high-frequency strategies where every second affects PnL.

Dashboard Development Stages

Stage Duration Result
Consultation and requirements gathering 1-2 days Technical specification
Interface prototyping 3-5 days Dashboard mockup
Backend (API, aggregation, WebSocket) 5-10 days Working endpoints
Frontend (charts, cards, filters) 5-10 days Dashboard interface
Integration and testing 3-5 days Acceptance, training

After implementing the dashboard, the average client increases profit by 15% due to timely stopping of unprofitable strategies. We have over 5 years in blockchain and developed dashboards for 50+ trading bots. We guarantee metric correctness and 99.9% uptime.

Example calculation on real data

Consider a bot on Binance with a $10,000 deposit. In one month, 200 trades: 120 profitable (average profit $50) and 80 losing (average loss $30). Profit factor = (12050)/(8030) = 6000/2400 = 2.5. Max drawdown = -8% (peak $11,200, bottom $10,304). Sharpe ratio = 1.8. These metrics indicate a stable strategy.

What Is Included in the Work

  • Analysis of your current data and metrics.
  • API design (REST + WebSocket).
  • Backend development in Python (FastAPI, PostgreSQL, Redis).
  • Frontend in React (Recharts, Tailwind).
  • Real-time monitoring integration.
  • Documentation, team training, 30-day support.

Order a dashboard for your crypto bot — get a free engineer consultation. Contact us for a bot metric audit. Savings on commissions and timely problem detection pay for the implementation within the first month.