...

Mastering Intraday Backtesting: Beyond the Daily Candle

Why most backtests fail, and how granular intraday data can save your strategy from the graveyard of overfitting.

Mastering Intraday Backtesting: Beyond the Daily Candle

Let’s look at a candle. Specifically, let's look at the Daily Candle for ETH/USD on May 19, 2021.

On a standard chart, it looks like a "Long-Legged Doji."

  • Open: $3,382.66
  • High: $3,437.94
  • Low: $1,952.46
  • Close: $2,460.68

To a textbook technician, this is a signal of "indecision." A neutral pause in the market. But if you zoom in—if you take a microscope to that single red bar—you don't see indecision. You see a war.

You see billions of dollars in liquidations. You see an order book vaporizing in milliseconds. You see arbitrage bots misfiring, stablecoins de-pegging by pennies, and latency arbitrageurs feasting on the chaos.

If you backtested a strategy on the "Daily" timeframe for that day, your bot saw a -27% move. If you backtested on the "1-minute" timeframe, your bot saw a minefield.

This is the central problem of algorithmic trading: The Resolution Trap. The map (Daily Data) is not the territory (Tick Data).

In trading forensics, the most dangerous place is the "wick." A daily candle might show a low of $1,950. But how did it get there?

Did it crash instantly and bounce (a "V-Shape" recovery)? Or did it grind down slowly, creating liquidity pools along the way, before squeezing shorts back up?

  • Scenario A (The Flash Crash): Price drops 40% in 15 minutes. Liquidity is non-existent. Slippage is infinite. If your stop loss triggered here, you didn't get out at your price. You got out 10% lower.
  • Scenario B (The Slow Bleed): Price drops 40% over 12 hours. Liquidity is thick. Stops are respected.

Two scenarios. Same "Daily Low." One kills your fund. The other makes you rich. Without high-definition data, you cannot distinguish the murder weapon.

Forensic analysis requires evidence. In our case, that evidence is Granular Data.

Most backtests assume a "Perfect Fill." In reality, fills are a function of Volatility and Volume. A sophisticated simulation doesn't just ask "What was the price?" It asks: "What was the cost of the price?" During the May 19th crash, spreads on major exchanges widened from $0.50 to $50.00. That’s 100x the normal cost of doing business. If your backtest didn't capture that, your Sharpe Ratio is a fiction.

The most common "crime" in code is Look-Ahead Bias. It’s like reading the ending of a mystery novel before solving the case. If your code says: if (close > open) Buy(), you are cheating. You don't know the "Close" until the day is over. You must solve the case in real-time. You must calculate your signal at Minute 1, then Minute 2, then Minute 3, never knowing what Minute 4 holds.

To convict a bad strategy, we need to recreate the crime scene. This simulation doesn't just check prices. It creates a "hostile environment" of fees, slippage, and spread widening to see if your alpha survives.

import { Configuration, CandlesApi } from "tickcatcher";
 
const config = new Configuration({ apiKey: process.env.TICKCATCHER_API_KEY });
const candlesApi = new CandlesApi(config);
 
async function performForensicBacktest(symbol: string) {
  // We define the "Hostility Parameters"
  const BASE_SPREAD = 0.0002; // 0.02%
  const PANIC_MULTIPLIER = 10; // During crashes, spreads explode 10x
  
  // We load the Tick Data (or 1m granular data)
  const evidence = await candlesApi.ultraCandles({
    symbol,
    timeframe: '1m', // The atomic unit of truth
    limit: 10000 
  });
 
  let balance = 10000;
  let position = 0;
 
  for (let i = 20; i < evidence.length; i++) {
    const minute = evidence[i];
    
    // Forensic Check: Is this a high-volatility minute?
    // We calculate the "Body Size" relative to recent average
    const volatility = (minute.high - minute.low) / minute.open;
    const isPanicMode = volatility > 0.02; // >2% move in 1 minute
    
    // Adjust Slippage based on the "Crime Scene" conditions
    const currentSlippage = isPanicMode ? BASE_SPREAD * PANIC_MULTIPLIER : BASE_SPREAD;
 
    // Strategy Logic (Simple Momentum)
    if (position === 0 && minute.close > evidence[i-1].high) {
      // ENTRY
      const fillPrice = minute.close * (1 + currentSlippage);
      position = balance / fillPrice;
      balance = 0;
    } else if (position > 0 && minute.close < evidence[i-1].low) {
      // EXIT
      const fillPrice = minute.close * (1 - currentSlippage);
      balance = position * fillPrice;
      position = 0;
    }
  }
 
  return balance;
}

The market is not a smooth curve. It is a fractal landscape of jagged edges. Most strategies look innocent on a Daily Chart. But when you run the forensics—when you force them to survive the tick-by-tick "war" of the real world—the truth comes out.

Don't assume. Investigate. Backtest with the evidence.

Ready to build what you just read?

Stop struggling with fragmented data. Access high-fidelity crypto market data, economic events, and historical depth instantly.