A New Metric for Evaluating Trading Bot Performance?
A New Metric for Evaluating Trading Bot Performance?
Hey all, I've been working on a new metric to better measure the performance of trading bots, particularly for something like Gunbot. I've always felt that traditional metrics like ROI (Return on Investment), CAGR (Compound Annual Growth Rate), or even the Sortino Ratio don't always give you the full picture when it comes to automated trading. They can be tricky to use, understand, and especially difficult when you're trying to compare the performance of different strategies across various assets.
Why Traditional Metrics Fall Short
ROI: Sure, ROI gives you a snapshot of profitability, but it doesn't tell you how long your capital was tied up or what kind of risk exposure you had. Two bots with the same ROI could have wildly different levels of risk or time commitment.
CAGR: I get it—CAGR is great for long-term investments, but when you're running a trading bot that's making decisions daily (or even hourly), it's tough to rely on an annualized metric. It’s hard to apply something designed for multi-year investments to something as dynamic as crypto trading.
Sortino Ratio: The Sortino Ratio is better than Sharpe when it comes to ignoring upside volatility, but it’s still not the easiest thing to explain or compare across different strategies. It's especially tricky when the assets you're trading have different volatility profiles, like comparing Bitcoin to a stablecoin or traditional stocks.
Because of these limitations, I started working on something that could more accurately reflect how well a bot is performing based on capital efficiency and duration of trades. And that’s where the Return on Bot (RoB) idea came in.
Return on Bot (RoB)
RoB is designed to give you a deeper insight into how effectively your bot is using the capital you’ve allocated. It factors in things like capital utilization over time, maximum capital utilized, and of course, the net profit generated. What I like about this is that it doesn’t just focus on profits but also on how efficiently those profits were made.
If you're using a crypto trading bot like Gunbot, it’s essential to track not just the end result, but also how your bot is managing your capital throughout the process. RoB helps answer important questions like "How much of my capital is being used at any given time?" and "Am I taking on unnecessary risk for the returns I'm getting?"
The Code
Here's the code I came up with for calculating RoB. It’s still in testing, but I think it’s pretty promising so far. It calculates total returns, daily returns, and adjusted returns, all while considering how much capital was used and for how long.
function calculateReturnOnBot(orders) {
// Sort orders by time to ensure chronological order
orders.sort((a, b) => a.time - b.time);
// Initialize variables
let positionSize = 0; // Total units held
let capitalUtilized = 0; // Capital tied up in open positions
let totalNetProfit = 0; // Sum of realized PnL
let totalWeightedCapitalUtilized = 0; // Sum of (Capital Utilized * Duration)
let totalDuration = 0; // Total time in milliseconds
let previousTime = orders[0].time; // Time of the first order
let maxCapitalUtilized = 0; // Maximum capital utilized
for (let i = 0; i < orders.length; i++) {
const order = orders[i];
const currentTime = order.time;
// Calculate duration since the previous order
const duration = currentTime - previousTime;
// Accumulate the weighted capital utilized
totalWeightedCapitalUtilized += capitalUtilized * duration;
// Accumulate total duration
totalDuration += duration;
// Update previousTime for the next iteration
previousTime = currentTime;
// Extract necessary fields from the order
const amount = parseFloat(order.amount);
const rate = parseFloat(order.rate);
const pnl = parseFloat(order.pnl);
if (order.type === "buy") {
// Update position size
positionSize += amount;
// Update capital utilized
capitalUtilized += amount * rate;
} else if (order.type === "sell") {
// Update total net profit
totalNetProfit += pnl;
// Update position size
positionSize -= amount;
// Update capital utilized
capitalUtilized -= amount * rate;
}
// Ensure capitalUtilized doesn't go negative due to rounding errors
capitalUtilized = Math.max(capitalUtilized, 0);
// Update the maximum capital utilized
maxCapitalUtilized = Math.max(maxCapitalUtilized, capitalUtilized);
}
// Handle the last time interval (assuming capital utilized remains the same after the last order)
const endTime = orders[orders.length - 1].time;
const finalDuration = endTime - previousTime;
totalWeightedCapitalUtilized += capitalUtilized * finalDuration;
totalDuration += finalDuration;
// Calculate average capital utilized
const averageCapitalUtilized = totalWeightedCapitalUtilized / totalDuration;
// Convert totalDuration from milliseconds to days
const millisecondsInDay = 24 * 60 * 60 * 1000;
const totalDurationInDays = totalDuration / millisecondsInDay;
// Calculate Return on Bot (RoB)
const returnOnBot = totalNetProfit / averageCapitalUtilized;
// Calculate daily Return on Bot as a percentage
const dailyReturnPercentage = (returnOnBot / totalDurationInDays) * 100;
// Calculate total return percentage over the trading period
const totalReturnPercentage = returnOnBot * 100;
// Adjusted Return on Bot using maximum capital utilized
const adjustedReturnOnBot = totalNetProfit / maxCapitalUtilized;
// Adjusted total return percentage
const adjustedTotalReturnPercentage = adjustedReturnOnBot * 100;
// Adjusted daily return percentage
const adjustedDailyReturnPercentage = (adjustedReturnOnBot / totalDurationInDays) * 100;
// Return the calculated metrics
return {
totalNetProfit: totalNetProfit,
averageCapitalUtilized: averageCapitalUtilized,
maxCapitalUtilized: maxCapitalUtilized,
totalReturnPercentage: totalReturnPercentage.toFixed(2),
dailyReturnPercentage: dailyReturnPercentage.toFixed(4),
adjustedTotalReturnPercentage: adjustedTotalReturnPercentage.toFixed(2),
adjustedDailyReturnPercentage: adjustedDailyReturnPercentage.toFixed(4),
totalDurationInDays: totalDurationInDays.toFixed(2)
};
}
I'd love to hear your feedback on this. Does RoB seem like something that would be useful for your trading strategies? I'm considering adding this as a feature in the next Gunbot release. Feel free to try it out and let me know what you think!