Williams Fractals Combined with ZZ Indicator for Quantitative Trading Strategies

Author: ChaoZhang, Date: 2024-01-29 15:24:30
Tags:

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.


/*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)

More