Developing a Better Way to Measure Trading Bot Performance

gunbot

peter post

Posted on September 29, 2024

Developing a Better Way to Measure Trading Bot Performance

I've been spending some time working on a new way to evaluate how well trading bots are performing. Metrics like ROI (Return on Investment), CAGR (Compound Annual Growth Rate), and even the Sortino Ratio are useful, but they don’t always capture the full scope of what happens in algo trading. When you're running a bot, especially in something as fast-paced as crypto, it can be hard to draw meaningful comparisons between different strategies using these traditional tools.

The Problem with Standard Performance Metrics

  • ROI: While ROI gives you a basic idea of profitability, it doesn’t factor in how long your capital is locked into a trade. Two bots could show the same ROI but have completely different risk profiles or trade durations. This can make it tough to know which bot is actually performing better.

  • CAGR: This works well for long-term investments, but if your bot is executing multiple trades daily, annualized growth rates don’t feel relevant. You lose a lot of granularity, especially when evaluating short-term or highly volatile assets.

  • Sortino Ratio: Although it's a solid improvement over the Sharpe Ratio by focusing on downside risk, the Sortino Ratio still doesn’t account for how strategies handle capital utilization over time. And when you're working across assets with different volatility (like Bitcoin vs. stablecoins), it can get even more complicated.

These traditional metrics just don’t seem to offer enough insight when trying to compare the performance of different bots across varying assets and strategies. To address this, I started developing a metric that factors in both capital efficiency and time in trade. That’s where the Return on Bot (RoB) metric comes in.

Introducing Return on Bot (RoB)

RoB offers a more nuanced way to evaluate your bot's performance. It calculates how efficiently your bot is using the capital you allocate to it. Instead of just focusing on end results (profits or losses), RoB digs into how your capital is utilized over the life of the bot's trades, as well as the maximum capital at risk at any given time.

If you're working with a crypto trading bot, understanding both how much of your capital is being used and whether that usage is efficient is key. RoB can answer questions like "How much of my allocated funds are tied up in trades?" and "Is my bot taking unnecessary risks for the returns it's generating?"

The Code Behind RoB

Here’s the code I came up with for calculating RoB. It's still being refined, but it already offers some valuable insights into bot performance. This approach calculates both total and daily returns, adjusted for capital utilization and the maximum capital tied up during trades.

function calculateReturnOnBot(orders) {
    orders.sort((a, b) => a.time - b.time);

    let positionSize = 0; // Units held
    let capitalUtilized = 0; // Capital tied up
    let totalNetProfit = 0; // Realized profit/loss
    let totalWeightedCapitalUtilized = 0; // Sum of (Capital Utilized * Duration)
    let totalDuration = 0; // Total time in milliseconds
    let previousTime = orders[0].time; // Time of first order
    let maxCapitalUtilized = 0; // Peak capital usage

    for (let i = 0; i < orders.length; i++) {
        const order = orders[i];
        const currentTime = order.time;
        const duration = currentTime - previousTime;

        totalWeightedCapitalUtilized += capitalUtilized * duration;
        totalDuration += duration;
        previousTime = currentTime;

        const amount = parseFloat(order.amount);
        const rate = parseFloat(order.rate);
        const pnl = parseFloat(order.pnl);

        if (order.type === "buy") {
            positionSize += amount;
            capitalUtilized += amount * rate;
        } else if (order.type === "sell") {
            totalNetProfit += pnl;
            positionSize -= amount;
            capitalUtilized -= amount * rate;
        }

        capitalUtilized = Math.max(capitalUtilized, 0);
        maxCapitalUtilized = Math.max(maxCapitalUtilized, capitalUtilized);
    }

    const endTime = orders[orders.length - 1].time;
    const finalDuration = endTime - previousTime;
    totalWeightedCapitalUtilized += capitalUtilized * finalDuration;
    totalDuration += finalDuration;

    const averageCapitalUtilized = totalWeightedCapitalUtilized / totalDuration;
    const millisecondsInDay = 24 * 60 * 60 * 1000;
    const totalDurationInDays = totalDuration / millisecondsInDay;

    const returnOnBot = totalNetProfit / averageCapitalUtilized;
    const dailyReturnPercentage = (returnOnBot / totalDurationInDays) * 100;
    const totalReturnPercentage = returnOnBot * 100;

    const adjustedReturnOnBot = totalNetProfit / maxCapitalUtilized;
    const adjustedTotalReturnPercentage = adjustedReturnOnBot * 100;
    const adjustedDailyReturnPercentage = (adjustedReturnOnBot / totalDurationInDays) * 100;

    return {
        totalNetProfit,
        averageCapitalUtilized,
        maxCapitalUtilized,
        totalReturnPercentage: totalReturnPercentage.toFixed(2),
        dailyReturnPercentage: dailyReturnPercentage.toFixed(4),
        adjustedTotalReturnPercentage: adjustedTotalReturnPercentage.toFixed(2),
        adjustedDailyReturnPercentage: adjustedDailyReturnPercentage.toFixed(4),
        totalDurationInDays: totalDurationInDays.toFixed(2)
    };
}
Enter fullscreen mode Exit fullscreen mode

I'd love to know what you think. Is Return on Bot something you’d use in your trading strategies? I’m considering adding it as a feature to Gunbot, but it’s still in development. Let me know your thoughts, and feel free to experiment with the code!

💖 💪 🙅 🚩
gunbot
peter post

Posted on September 29, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related