← Back to Home
ZigZag Strategy Backtest: Turning ETH-USD Volatility Into an 86.58% Return

ZigZag Strategy Backtest: Turning ETH-USD Volatility Into an 86.58% Return

Get the full strategy library: This case study uses one strategy from the Mega Backtrader Strategy Pack, a package of 500+ Backtrader-ready Python trading strategies with batch backtesting, dashboards, metrics, charts, and documentation.

Download the package here: Mega Backtrader Strategy Pack

If you want to stop building strategies from scratch and start testing hundreds of ready-made systems across stocks, crypto, ETFs, and other markets, this is the package built for that workflow.

Ethereum is volatile. That volatility can punish simple buy-and-hold entries, but it also creates structure: swing highs, swing lows, breakouts, reversals, support, and resistance.

This article walks through ZigZagStrategy, one of the strategies included in the Mega Backtrader Strategy Pack. The strategy was tested on ETH-USD daily candles from July 23, 2025 to July 23, 2026.

The result:

Result Value
Strategy return 86.58%
ETH buy-and-hold return -48.06%
Excess return 134.64%
Sharpe ratio 2.49
Max drawdown 7.27%
Closed trades 16
Open trades 0
Win rate 56.25%

This is exactly the kind of strategy case study the package is built for: take a real strategy module, run it through the batch framework, inspect the code, publish the results, and show the charts.

Strategy Idea

ZigZagStrategy tries to turn noisy price action into tradable swing structure.

It does four things:

  1. Detects ZigZag swing highs and swing lows using a percentage reversal threshold.
  2. Builds support and resistance levels from repeated pivots.
  3. Looks for recognizable patterns such as double tops, double bottoms, ascending triangles, and descending triangles.
  4. Uses volume confirmation and trailing stops to validate breakouts and manage risk.

The core idea is simple: do not trade every candle. Wait for meaningful swing structure, then trade confirmed breakouts or reversals.

Strategy Parameters

The strategy exposes its behavior through Backtrader params:

params = (
    ('zigzag_pct', 0.01),
    ('pattern_lookback', 7),
    ('support_resistance_strength', 2),
    ('breakout_volume_multiplier', 1.2),
    ('volume_period', 7),
    ('trailing_stop_pct', 0.02),
)

These settings define:

Code Walkthrough

The strategy first tracks price and volume:

self.high = self.data.high
self.low = self.data.low
self.close = self.data.close
self.volume = self.data.volume
self.volume_sma = bt.indicators.SMA(
    self.volume,
    period=self.params.volume_period,
)

It then maintains internal ZigZag state:

self.zigzag_points = []
self.current_direction = 0
self.current_extreme = None
self.support_levels = []
self.resistance_levels = []

The ZigZag engine identifies reversals when price moves far enough from the prior extreme:

if self.current_direction == 1:
    if current_high > prev_high:
        self.current_extreme = (current_bar, current_high, current_low)
    elif current_low < prev_high * (1 - threshold):
        self.add_zigzag_point(prev_bar, prev_high, 'high')
        self.current_direction = -1
        self.current_extreme = (current_bar, current_high, current_low)

Support and resistance levels are built from repeated pivot zones:

if point_type == 'low':
    for i, (level, count) in enumerate(self.support_levels):
        if abs(price - level) / level < tolerance:
            self.support_levels[i] = (level, count + 1)
            support_confirmed = True
            break

The pattern recognition logic checks common market structures. For example, a double bottom is detected when two lows form near the same area with a high between them:

if abs(low1 - low2) / max(low1, low2) < self.params.zigzag_pct:
    return {
        'type': 'double_bottom',
        'support': min(low1, low2),
        'resistance': high_between,
    }

The actual trading logic then requires volume confirmation:

volume_confirmation = (
    self.volume[0] >
    self.volume_sma[0] * self.params.breakout_volume_multiplier
)

If a double bottom breaks above resistance with volume, the strategy buys:

if pattern['type'] == 'double_bottom' and volume_confirmation:
    if current_price > pattern['resistance'] and not self.position:
        self.order = self.buy()

If a double top breaks below support with volume, the strategy sells:

elif pattern['type'] == 'double_top' and volume_confirmation:
    if current_price < pattern['support'] and not self.position:
        self.order = self.sell()

The strategy also trades support/resistance breakouts when no named pattern is active:

if nearest_resistance and volume_confirmation:
    if current_price > nearest_resistance * 1.001 and not self.position:
        self.order = self.buy()

Risk is managed with a trailing stop that adjusts as the trade moves in the strategy's favor:

new_stop_price = self.highest_price_since_entry * (
    1 - self.params.trailing_stop_pct
)

if new_stop_price > self.trailing_stop_price:
    self.trailing_stop_price = new_stop_price
    self.cancel(self.stop_order)
    self.stop_order = self.sell(
        exectype=bt.Order.Stop,
        price=self.trailing_stop_price,
    )

That makes the strategy more than a simple pattern detector. It has pivot detection, pattern logic, volume confirmation, support/resistance handling, and active stop management.

Backtest Command

The article result was generated with:

python run_backtest.py --fast --fast-plots --fast-equity --refresh-data \
  --workers 1 \
  --symbol ETH-USD \
  --period 1y \
  --interval 1d \
  --benchmark ETH-USD \
  --stake-percent 99 \
  --strategies strategies \
  --out results \
  --strategy-filter ZigZagStrategy

Backtest setup:

Setting Value
Asset ETH-USD
Benchmark ETH-USD buy-and-hold
Period 1y
Data window July 23, 2025 to July 23, 2026
Interval 1d
Starting cash $10,000
Final value $18,657.72
Strategy file strategies/ZigZagStrategy.py

Results

Metric Value
Strategy return 86.58%
ETH buy-and-hold return -48.06%
Excess return vs benchmark 134.64%
Sharpe ratio 2.49
Max drawdown 7.27%
Total trades 16
Closed trades 16
Open trades 0
Winning trades 9
Losing trades 7
Win rate 56.25%
Runtime 2.41 seconds

The strategy did not need hundreds of trades to produce the result. It made 16 closed trades, won slightly more than half of them, and kept drawdown controlled while ETH buy-and-hold struggled over the same period.

Equity Curve vs Benchmark

ZigZag ETH-USD equity curve versus ETH buy-and-hold benchmark

The equity curve shows the strategy compounding from $10,000 to $18,657.72 while the ETH-USD benchmark declined over the same window.

Drawdown vs Benchmark

ZigZag ETH-USD drawdown versus benchmark

The drawdown chart shows how risk was contained during the test. The strategy's maximum drawdown was 7.27%, while buy-and-hold carried much deeper downside exposure.

Rolling Return vs Benchmark

ZigZag ETH-USD rolling return versus benchmark

The rolling return chart shows how the strategy's edge developed over the backtest window instead of depending on only one isolated trade.

Daily Return Distribution

ZigZag ETH-USD daily returns histogram

The daily return distribution gives a compact view of how the strategy's day-to-day returns were shaped during the test.

What This Shows

This strategy is a good example of why a large Backtrader library is useful.

Instead of starting from a blank file, the package gives you a complete research loop:

  1. Pick a strategy module from the catalog.
  2. Run it on an asset and timeframe.
  3. Compare it against buy-and-hold.
  4. Inspect the source code.
  5. Review charts, drawdown, returns, and trade counts.
  6. Turn the result into a case study, report, or trading research note.

For this ETH-USD run, the ZigZag approach worked well because it was built for swing structure. It did not blindly hold through the whole market move. It reacted to pivots, patterns, support/resistance, volume confirmation, and trailing stops.

Get the Complete Strategy Library

ZigZagStrategy is one of 500+ Backtrader-ready strategies included in the Mega Backtrader Strategy Pack.

Get the full package here: Mega Backtrader Strategy Pack

The package includes:

This makes it possible to publish many strategy articles like this one:

The package is not just a folder of code. It is a repeatable content and research engine for systematic trading strategy analysis.

If you want the same workflow used in this article, download the full package:

Get the Mega Backtrader Strategy Pack

Disclaimer

This article is for research and educational use only. Backtest results are not financial advice, investment advice, or a guarantee of future performance. Always validate strategy logic, data quality, execution assumptions, costs, slippage, and risk before using any trading system.