0bps

Strategy vault / Machine learning

Williams Fractals Combined with ZZ Indicator for Quantitative Trading Strategies

This is a quantitative trading strategy that combines the use of Bill Williams' fractal theory and the ZZ indicator. It judges market trends through the calculation of Williams fractals and identifies potential…

Author
ChaoZhang
Complexity
Intermediate · 105 lines
Parameters
10
Backtest bar
1h · intraday
Tested on
BTC/USDT · futures

IMG

Overview

This is a quantitative trading strategy that combines the use of Bill Williams' fractal theory and the ZZ indicator. It judges market trends through the calculation of Williams fractals and identifies potential breakout points by drawing support/resistance lines using the ZZ indicator to implement trend-following trades.

Strategy Principle

The strategy first calculates the Williams fractals to determine whether the current fractal is rising or falling. If it is a rising fractal, it is believed that the current trend is upward. If it is a falling fractal, it is believed that the current trend is downward.

It then draws ZZ indicator's support and resistance lines based on the fractal points. If the price breaks through the resistance line corresponding to the rising fractal, go long. If the price breaks through the support line corresponding to the falling fractal, go short.

Through such a combination, it is possible to capture changes in trends in a timely manner and implement trend-following trades.

Advantage Analysis

This strategy combines two different technical analysis methods - Williams fractals and ZZ indicators - to uncover more trading opportunities.

It can timely judge the turning point of market trends and has good stop loss/take profit criteria to capture the main trend direction. In addition, the ZZ indicator can filter out some false breakouts to avoid unnecessary losses.

In general, this strategy considers both trend judgment and specific entry point selections to balance risks and returns.

Risk Analysis

The biggest risk of this strategy is that fractal judgments and ZZ indicator may issue wrong trading signals, leading to unnecessary losses. For example, after breaking through the resistance line, prices may quickly fall back, unable to sustain the uptrend.

In addition, the way fractals are calculated can lead to misjudgments if the timeframe is set improperly. Setting the timeframe too short increases the probability of false breakouts.

To reduce these risks, appropriately adjust the calculation parameters of fractals and increase filtering conditions to reduce erroneous signals. Besides, set wider stop loss to control single trade loss size.

Optimization Directions

This strategy can be further optimized in the following aspects:

  1. Add momentum indicator filters such as MACD or Bollinger Bands to avoid some false breakouts.

  2. Optimize fractal parameter settings and adjust the calculation of highs and lows and shorten the timeframe to obtain more accurate trend judgments.

  3. Increase machine learning algorithms to judge trend accuracy and avoid human limitations.

  4. Add adaptive stop loss mechanism based on market volatility.

  5. Use deep learning algorithms to optimize overall parameter settings.

Summary

By skillfully combining Williams' fractal theory and the ZZ indicator, this strategy achieves timely detection and capturing of changes in market trends. It maintains high win rate and expects to obtain long-term excess returns. Next step by introducing more filters and AI capabilities, it is expected to further improve strategy stability and return rate.

Parameters

NameDefaultWhat it controls
v_input_1trueLong
v_input_2falseShort
v_input_3falsefilter Bill Williams Fractals
v_input_4trueShow levels
v_input_5trueShow fractals (repaint!)
v_input_6trueShow dots (repaint!)
v_input_7falseShow background
v_input_8falseShow drawdown
v_input_9timestamp(01 Jan 2000 00:00 +0000)Start Time
v_input_10timestamp(31 Dec 2099 23:59 +0000)Final Time

Source Pine Script

/*backtest
start: 2023-12-01 00:00:00
end: 2023-12-31 23:59:59
period: 1h
basePeriod: 15m
exchanges: [{"eid":"Futures_Binance","currency":"BTC_USDT"}]
*/

//@version=4
strategy(title = "robotrading ZZ-8 fractals", shorttitle = "ZZ-8", overlay = true, default_qty_type = strategy.percent_of_equity, initial_capital = 100, default_qty_value = 100, commission_value = 0.1)

//Settings
needlong  = input(true, defval = true, title = "Long")
needshort = input(false, defval = true, title = "Short")
filterBW = input(false, title="filter Bill Williams Fractals")
showll = input(true, title = "Show levels")
showff = input(true, title = "Show fractals (repaint!)")
showdd = input(true, title = "Show dots (repaint!)")
showbg = input(false, title = "Show background")
showlb = input(false, title = "Show drawdown")
startTime = input(defval = timestamp("01 Jan 2000 00:00 +0000"), title = "Start Time", type = input.time, inline = "time1")
finalTime = input(defval = timestamp("31 Dec 2099 23:59 +0000"), title = "Final Time", type = input.time, inline = "time1")

//Variables
loss = 0.0
maxloss = 0.0
equity = 0.0
truetime = true

//Fractals
isRegularFractal(mode) =>
    ret = mode == 1 ? high[4] < high[3] and high[3] < high[2] and high[2] > high[1] and high[1] > high[0] : mode == -1 ? low[4] > low[3] and low[3] > low[2] and low[2] < low[1] and low[1] < low[0] : false
isBWFractal(mode) =>
    ret = mode == 1 ? high[4] < high[2] and high[3] <= high[2] and high[2] >= high[1] and high[2] > high[0] : mode == -1 ? low[4] > low[2] and low[3] >= low[2] and low[2] <= low[1] and low[2] < low[0] : false
filteredtopf = filterBW ? isRegularFractal(1) : isBWFractal(1)
filteredbotf = filterBW ? isRegularFractal(-1) : isBWFractal(-1)

//Triangles
plotshape(filteredtopf and showff, title='Filtered Top Fractals', style=shape.triangledown, location=location.abovebar, color= color.red, offset=-2)
plotshape(filteredbotf and showff, title='Filtered Bottom Fractals', style=shape.triangleup, location=location.belowbar, color= color.lime, offset=-2)

//Levels
hh = 0.0
ll = 0.0
hh := filteredtopf ? high[2] : hh[1]
ll := filteredbotf ? low[2] : ll[1]

//Trend
trend = 0
trend := high >= hh[1] ? 1 : low <= ll[1] ? -1 : trend[1]

//Lines
hcol = showll and hh == hh[1] and close < hh ? color.lime : na
lcol = showll and ll == ll[1] and close > ll ? color.red : na
plot(hh, color = hcol)
plot(ll, color = lcol)

//Dots
// var line hline = na
// if hh != hh[1] and showdd
//     hline := line.new(bar_index - 0, hh[0], bar_index - 2, hh[0], xloc = xloc.bar_index, extend = extend.none, style = line.style_dotted, color = color.lime, width = 1)
// var line lline = na
// if ll != ll[1] and showdd
//     lline := line.new(bar_index - 0, ll[0] - syminfo.mintick, bar_index - 2, ll[0] - syminfo.mintick, xloc = xloc.bar_index, extend = extend.none, style = line.style_dotted, color = color.red, width = 1)
    
//Background
bgcol = showbg == false ? na : trend == 1 ? color.lime : trend == -1 ? color.red : na
bgcolor(bgcol, transp = 80)

//Orders
if hh > 0 and needlong
    strategy.entry("Long", strategy.long, na, stop = hh, when = needlong and truetime)
    strategy.exit("Exit Long", "Long", stop = ll, when = needshort == false)
if ll > 0 and startTime
    strategy.entry("Short", strategy.short, na, stop = ll, when = needshort and truetime)
    strategy.exit("Exit Short", "Short", stop = hh, when = needlong == false)
if time > finalTime
    strategy.close_all()
    strategy.cancel("Long")
    strategy.cancel("Short")

if showlb

    //Drawdown
    max = 0.0
    max := max(strategy.equity, nz(max[1]))
    dd = (strategy.equity / max - 1) * 100
    min = 100.0
    min := min(dd, nz(min[1]))
    
    //Max loss size
    equity := strategy.position_size != strategy.position_size[1] ? strategy.equity : equity[1]
    loss := equity < equity[1] ? ((equity / equity[1]) - 1) * 100 : 0
    maxloss := min(nz(maxloss[1]), loss)
    
    //Label
    min := round(min * 100) / 100
    maxloss := round(maxloss * 100) / 100
    labeltext = "Drawdown: " + tostring(min) + "%" + "\nMax.loss " + tostring(maxloss) + "%"
    var label la = na
    label.delete(la)
    tc = min > -100 ? color.white : color.red
    osx = timenow + round(change(time)*50)
    osy = highest(100)
    la := label.new(x = osx, y = osy, text = labeltext, xloc = xloc.bar_time, yloc = yloc.price, color = color.black, style = label.style_labelup, textcolor = tc)

Published by ChaoZhang on the FMZ strategy square · last modified 2024-01-29. Collected in the Quant Trading Vault. Unvalidated research: re-test with your own data and costs before trusting it.

Build this with AgenKit

A spec is not a trading system. Paste this into your coding agent and AgenKit runs a specialist team — architecture, test-first build, risk gates, review — with paper trading on by default.

in Claude Code, Cursor, Codex & 4 more
/agenkit build a production-grade trading bot with a backtest engine, risk controls and paper trading by default from strategies/Williams-Fractals-Combined-with-ZZ-Indicator-for-Quantitative-Trading-Strategies.md
  1. npx agenkit install engineering-kit in your project
  2. Paste the command into your agent and approve each phase
  3. Get tests, backtest, risk controls and a paper-trading switch

Understand it first

Before you run this, read the lesson behind the idea and how to backtest it honestly. Specs like this one are the survivors of an unknown number of trials; deflate their results accordingly.

Related specs

esc

Try , , or .

↑↓ move↵ open