Williams Fractal Trailing Stops For ThinkOrSwim

mbrennan5

New member
Author states:
Unlike the built-in version, you can configure how many bars it takes to confirm a fractal. This indicator plots all Williams high and low fractals, and a stop line that trails the fractals up and down. Includes long and short stop alerts. You can choose whether the trail flips long-short based on the price being exceeded within a candle or on candle close. This indicator deals only with fractals and doesn't get into the Alligator or anything else.

Vo8eNTW.png


Williams Fractal Trailing Stops
https://in.tradingview.com/script/JZXkmCi2-Williams-Fractal-Trailing-Stops/
 
Last edited by a moderator:

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Williams Fractal Trailing Stops
https://in.tradingview.com/script/JZXkmCi2-Williams-Fractal-Trailing-Stops/

"Unlike the built-in version, you can configure how many bars it takes to confirm a fractal (forward and backward lookbacks seperate inputs). This indicator plots all Williams high and low fractals, and a stop line that trails the fractals up and down."

Code:
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © SimpleCryptoLife
//@version=4

// ============================== ABOUT THIS SCRIPT ==================================

// == Description ==
// This indicator finds all Williams high and low fractals and marks them on the chart.
// You can configure how many bars backwards and forwards should be counted in order to confirm a fractal.
// You can also plot a stop line that trails the fractals up and down.
// You can choose whether the trail flips long-short based on the price being exceeded within a candle or on candle close.
// Includes alerts for crossing the long and short trailing stops.
// This indicator displays over the main chart.

// == Usage ==
// Works on all markets and timeframes, but it doesn't make much sense on really small timeframes or on assets with very low prices for their denominations (like very low-sat cryptos).
// This indicator is not intended to be used to generate entries and exits on its own. It can quickly show approximate market structure.
// For example, if you want to go long, but price hasn't broken the short trail yet, it's a reminder to be aware that price is yet to make a higher high.

// == Alerts==
// Crossed Williams Long Stop: Alerts when the selected price source exceeds an active long trail
// Crossed Williams Short Stop: Alerts when the selected price source exceeds an active short trail

// == Repainting ==
// Williams fractals can only be confirmed a number of bars after they form. So this indicator must repaint in the sense of going back to mark them once they're confirmed.
// After a fractal has been confirmed and marked, nothing is altered in that bar or any of the previous bars.

// == Credits ==
// Thanks to reading the highest()/lowest() function replacement script by the brilliant Ricardo Santos I finally understood why mine wasn't working.
// All code is my own.

// == Disclaimer ==
// You retain full responsibility for your trading at all times. Before trading with actual money, first make sure your risk management is professional-level.


study(title="Williams Fractal Trailing Stops", shorttitle="Williams Trailing Stops", overlay=true, linktoseries=true)

bool inputShowWilliamsFractals = input(defval=true, title="Show All Williams Fractals", type=input.bool, group="Display", tooltip="Displays little triangles above/below each Williams fractal")
bool inputShowWilliamsStops = input(defval=true, title="Show Williams Trailing Stop", type=input.bool, tooltip="Displays a trailing stop based on the most recent fractal")
bool inputShowWilliamsStopPrice = input(defval=true, title="Show Current Price of Williams Trailing Stop", type=input.bool, tooltip="Displays a price label for the current active stop")
int inputWilliamsLeftRange = input(defval=2, minval=1, maxval=50, title="Williams Fractal Range Back", group="Fractal Settings", tooltip="How many bars back to measure for the range. Traditionally, two bars back and two bars forward are used.")
int inputWilliamsRightRange = input(defval=2, minval=1, maxval=50, title="Williams Fractal Range Forwards", tooltip="How many bars forwards to measure for the range. Traditionally,an equal number of bars two bars back and two bars forward are used.")
float inputWilliamsStopBufferInput = input(defval=0, minval=0, maxval=20, step=0.5, title="Buffer for Williams Stops %", type=input.float, group="Advanced",
  tooltip="Adds a buffer between the actual fractal price and the trail, as a percentage of the fractal price")
string inputWilliamsFlipInput = input(title="Flip Trail on:", defval="Close", options=["Close","Wick"], tooltip="Defines which measurement of the candle (high/low, or close) must exceed the trail for it to flip.")


// ============================== WILLIAMS PRICE FRACTALS: CALCULATE AND PLOT FRACTALS ==================================

f_IsWilliamsFractal(_williamsLeftRange, _williamsRightRange, _type) =>
    // This function checks whether a Williams High/Low has formed. If so, it returns a bool true for Yes, the number of bars back from the current bar that the fractal formed, and the value of the fractal.
    // Note: Because fractals are always confirmed a known number of bars after the fact, we have to be careful when using this bool to look up values later.
    _isWilliamsFractal = (_type == "high" and high[_williamsRightRange] >= highest(high,_williamsLeftRange+_williamsRightRange+1))
      or (_type == "low" and low[_williamsRightRange] <= lowest(low,_williamsLeftRange+_williamsRightRange+1))  // Passing in the _type allows us to use just one function to do both highs and lows
    _fractalValue = _isWilliamsFractal and _type == "high" ? high[_williamsRightRange] : _isWilliamsFractal and _type == "low" ? low[_williamsRightRange] : na
    [_isWilliamsFractal,_fractalValue]

// Check if current bar confirms a Williams High or Low
[isWilliamsHigh,williamsHighPrice] = f_IsWilliamsFractal(inputWilliamsLeftRange, inputWilliamsRightRange, "high")
[isWilliamsLow,williamsLowPrice] = f_IsWilliamsFractal(inputWilliamsLeftRange, inputWilliamsRightRange, "low")

// Suppress fractals if the previous bar was a fractal. This will take care of the edge case where you have two bars closing at the same price in a row.
isWilliamsHigh := isWilliamsHigh[1] ? false : isWilliamsHigh
isWilliamsLow := isWilliamsLow[1] ? false : isWilliamsLow

// Plot the fractal shapes. They need to be offset backwards so they appear over the correct bar.
williamsHighOffset = 0 - inputWilliamsRightRange // Using this variable is a workaround because if you add -inputWilliamsRightRange to the offset it doesn't work
color white10 = color.new(color.white,10)  // Define a new colour with transparency of 10 to avoid compilation warnings
plotshape(isWilliamsHigh and inputShowWilliamsFractals, title="Shape for Williams High", style=shape.triangledown, location=location.abovebar, color=white10, size=size.tiny, offset=williamsHighOffset)
williamsLowOffset = 0 - inputWilliamsRightRange
plotshape(isWilliamsLow and inputShowWilliamsFractals, title="Shape for Williams Low", style=shape.triangleup, location=location.belowbar, color=white10, size=size.tiny, offset=williamsLowOffset)


// ============================== WILLIAMS PRICE FRACTALS: CALCULATE AND PLOT TRAILING STOP LINES ==================================

f_addPercentBuffer(_input, _buffer, _direction) =>
    // This function adds/removes a percentage buffer to/from the input. It's easy enough to include the calculation each time but I was on a roll with functions by this point.
    _direction == "plus" ? _input * (1 + (_buffer / 100)) :
      _direction == "minus" ? _input * (1 - (_buffer / 100)) : na

// Add the percentage buffer to the fractal price.
williamsLowPriceBuffered = f_addPercentBuffer(williamsLowPrice,inputWilliamsStopBufferInput,"minus")
williamsHighPriceBuffered = f_addPercentBuffer(williamsHighPrice,inputWilliamsStopBufferInput,"plus")

f_persistAndReset(_trigger, _source) =>
    // This function returns the value of _source when _trigger is true, persists it, and resets it to the new value of _source when _trigger is true again.
    var float _output = 0.0
    _output := _trigger ? _source : _output[1]

// Persist the buffered stop price and reset it each time there is a new fractal
williamsLongStopPrice = f_persistAndReset(isWilliamsLow,williamsLowPriceBuffered)
williamsShortStopPrice = f_persistAndReset(isWilliamsHigh,williamsHighPriceBuffered)

f_trail(_source, _trail, _direction) =>
    // This function trails the source series up or down.
    // Note: depending what you're trailing, and how you're resetting it later, you might want to test against _trail[0] instead of _trail[1]
    _direction == "down" and _source >= _trail[1] ? _trail : _direction == "up" and _source <= _trail[1] ? _trail : _source

// Need to declare these variables here, in the global scope, so we can use them in other functions later
var float williamsLongStopPriceTrail = williamsLongStopPrice
var float williamsShortStopPriceTrail = williamsShortStopPrice

// Trail the high (short) stop down and the low (long) stop up
williamsShortStopPriceTrail := f_trail(williamsShortStopPrice, williamsShortStopPriceTrail, "down")
williamsLongStopPriceTrail := f_trail(williamsLongStopPrice, williamsLongStopPriceTrail, "up")

f_flip(_flipInput, _longTrail, _shortTrail, _longReset, _shortReset) =>
    // This function flips from a trailing long stop to a trailing short stop and vice-versa. It takes the following inputs:
        // _flipInput - A string that defines whether to consider a touch of the stop line as a flip, or a close beyond it
        // _longTrail - The long trailing stop (trails up, below the price)
        // _shortTrail - The short trailing stop (trails down, above the price)
        // _longReset - The value to reset the long stop to, when it's hit
        // _shortReset - The value to reset the short stop to, when it's hit
    // The function returns the following outputs:
        // _longTrailOutput - The long trailing stop. Normally the same as it was input, unless it's reset.
        // _shortTrailOutput - The short trailing stop. Normally the same as it was input, unless it's reset.
        // _longTrailPlot - The long trailing stop to plot. This is na if we are not long.
        // _shortTrailPlot - The short trailing stop to plot. This is na if we are not short.
    //
    // These variables say whether we are flipping long or short this very bar. Usually they are both false. Only one of them can be true at once.
    var bool _flipLongNow = false
    var bool _flipShortNow = false
    // These variables say what state we're in: long or short. One or both are always true.
    // In the beginning, we haven't hit any trails yet, so we start off both long and short, to display both lines.
    var bool _isLong = true
    var bool _isShort = true
    // Get the source, depending whether it's on close or on touch
    float _flipLongSource = _flipInput == "Close" ? close : _flipInput == "Wick" ? high : na
    float _flipShortSource = _flipInput == "Close" ? close : _flipInput == "Wick" ? low : na
    // Are we flipping long or short this bar?
    _flipLongNow := _isShort[1] and _flipLongSource > _shortTrail ? true : false
    _flipShortNow := _isLong[1] and _flipShortSource < _longTrail ? true : false
    // In the edge case where we manage to flip both long and short, we need to reset that based on the close. The close is definitive for history and intra-candle it will take the current value.
    _flipLongNow := _flipShortNow and _flipLongNow and close > _longTrail ? true :  _flipShortNow and _flipLongNow and close <= _longTrail ? false : _flipLongNow
    _flipShortNow := _flipLongNow and _flipShortNow and close < _shortTrail ? true : _flipShortNow and _flipLongNow and close >= _shortTrail ? false : _flipShortNow
    // Set the long and short state variables. Set if we flip (simple), initialise to true if this is the first time (needed), otherwise persist.
    _isLong := _flipLongNow ? true : _flipShortNow ? false : na(_isLong[1]) ? true : _isLong[1]
    _isShort := _flipShortNow ? true : _flipLongNow ? false : na(_isShort[1]) ? true : _isShort[1]
    // Update the trailing price. If we flip this bar, reset to the nearest fractal - which goes against the trail direction, which is why we need to use another series.
    _longTrailOutput = _longTrail
    _shortTrailOutput = _shortTrail
    _longTrailOutput := _isLong and not _isLong[1] ? _longReset : _longTrailOutput
    _shortTrailOutput := _isShort and not _isShort[1] ? _shortReset : _shortTrailOutput
    // Hide the trailing long stop if we are short, and hide the trailing short stop if we are long. Show both if we are both long and short.
    float _longTrailPlot = _isLong ? _longTrailOutput : _isLong and _isShort ? _longTrailOutput : na
    float _shortTrailPlot = _isShort ? _shortTrailOutput : _isLong and _isShort ? _shortTrailOutput: na
    [_longTrailOutput, _shortTrailOutput, _longTrailPlot, _shortTrailPlot]

f_getFlipResetWilliamsLong(_longTrail, _buffer, _isWilliamsLow, _williamsRightRange) =>
    // This function gets the long stop price to reset to. This is unnecessary for ATR trails, but Williams fractals trails are more complicated.
    // The fractal that we would reset to is not always confirmed at the time we flip, so we take the lower of the last confirmed fractal and the Lows of the intervening bars.
    _barIndexWhenLastFractalConfirmed = valuewhen(_isWilliamsLow, bar_index, 0)     // Get the number of bars since the last fractal was confirmed (not formed)
    _barsSinceLastFractalConfirmed = bar_index - _barIndexWhenLastFractalConfirmed      // And get the total number of bars back to go from the current bar
    int _barsToGoBack = _barsSinceLastFractalConfirmed + _williamsRightRange       // Then add the number of bars in the Williams lag
    // Go that number of bars back and get the lowest low
    float _lowestLow = low
    for i = 0 to _barsToGoBack
        _lowestLow := min(low[i], _lowestLow)
    _lowestLowAdjusted = _lowestLow * (1 - (_buffer / 100))

f_getFlipResetWilliamsShort(_shortTrail, _buffer, _isWilliamsHigh, _williamsLeftRange) =>
    // This function is the short stop equivalent of f_getFlipResetWilliamsLong
    _barIndexWhenLastFractalConfirmed = valuewhen(_isWilliamsHigh, bar_index, 0)
    _barsSinceLastFractalConfirmed = bar_index - _barIndexWhenLastFractalConfirmed
    int _barsToGoBack = _barsSinceLastFractalConfirmed + _williamsLeftRange
    float _highestHigh = high
    for i = 0 to _barsToGoBack
        _highestHigh := max(high[i], _highestHigh)
    _highestHighAdjusted = _highestHigh * (1 + (_buffer / 100))

// Get the long/short stop price to reset to. It's normally the most recent opposing fractal, but the function takes care of edge cases where the most recent fractal isn't confirmed yet.
williamsLongStopPrice := f_getFlipResetWilliamsLong(williamsLongStopPrice, inputWilliamsStopBufferInput, isWilliamsLow, inputWilliamsRightRange)
williamsShortStopPrice := f_getFlipResetWilliamsShort(williamsShortStopPrice, inputWilliamsStopBufferInput, isWilliamsHigh, inputWilliamsRightRange)

// Get the plots for the trails, to show only long stop when long and short stop when short.
[williamsLongStopPriceTrailTemp, williamsShortStopPriceTrailTemp, williamsLongStopPriceTrailPlot, williamsShortStopPriceTrailPlot] =
  f_flip(inputWilliamsFlipInput, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice)

// Have to have these variables back in the global scope so we can persist them and use them as inputs to the function next bar.
// I don't think there's a way round this because assigning multiple mutable variables via a function doesn't seem to work.
williamsLongStopPriceTrail := williamsLongStopPriceTrailTemp
williamsShortStopPriceTrail := williamsShortStopPriceTrailTemp

// Hide trailing stop plots if the user selected that (input bool inputShowWilliamsStops)
williamsShortStopPriceTrailPlotDisplay = inputShowWilliamsStops ? williamsShortStopPriceTrailPlot : na
williamsLongStopPriceTrailPlotDisplay = inputShowWilliamsStops ? williamsLongStopPriceTrailPlot : na

// Plot the trailing stops
color yellow50 = color.new(color.yellow,50), color yellow0 = color.new(color.yellow,0)
color orange50 = color.new(color.orange,50), color orange0 = color.new(color.orange,0)
plot(williamsShortStopPriceTrailPlotDisplay, "Williams Trailing Stop High Price", color=yellow50, style=plot.style_linebr, linewidth=3)
plot(williamsShortStopPriceTrailPlotDisplay, "Williams Trailing Stop High Price Highlight", color=yellow0, style=plot.style_linebr, linewidth=1)
plot(williamsLongStopPriceTrailPlotDisplay, "Williams Trailing Stop Low Price", color=orange50, style=plot.style_linebr, linewidth=3)
plot(williamsLongStopPriceTrailPlotDisplay, "Williams Trailing Stop Low Price Highlight", color=orange0, style=plot.style_linebr, linewidth=1)


// ============================== WILLIAMS PRICE FRACTALS: PRINT PRICE LABEL ==================================

// If the user hides trailing stop lines, OR hides the price label, don't print the label
// If we are long, print a label below the trailing stop line. If we are short, print a label above the trailing stop line.

label williamsLongStopPriceLabel = if inputShowWilliamsStopPrice and not na(williamsLongStopPriceTrailPlotDisplay)
    label.new(bar_index, na, 'Long stop price: \n' + tostring(williamsLongStopPriceTrailPlotDisplay), color=color.gray, textcolor=color.white, style=label.style_labelup, yloc=yloc.belowbar)
else
    na

label williamsShortStopPriceLabel = if inputShowWilliamsStopPrice and not na(williamsShortStopPriceTrailPlotDisplay)
    label.new(bar_index, na, 'Short stop price: \n' + tostring(williamsShortStopPriceTrailPlotDisplay), color=color.gray, textcolor=color.white, style=label.style_labeldown, yloc=yloc.abovebar)
else
    na

// Delete the previous long/short label, i.e. only keep the current one
label.delete(williamsLongStopPriceLabel[1])
label.delete(williamsShortStopPriceLabel[1])


// ============================== WILLIAMS PRICE FRACTALS: ALERTS ==================================


// Alert for crossing the trailing stop. You can set this to trigger Once, or Once per bar close, in the TradingView alert configuration screen. You can use this for soft stops or to look for entries.
// Calculate if we crossed a trailing line. Not going to do the calculation again, just cheat and use the plot that we did before.
// Have to choose the right one. It does matter that it was shown and hidden according to the flip, but it doesn't matter if the user hid it.
alertCrossWilliamsLongStop = na(williamsLongStopPriceTrailPlot) and not na(williamsLongStopPriceTrailPlot[1])
alertCrossWilliamsShortStop = na(williamsShortStopPriceTrailPlot) and not na(williamsShortStopPriceTrailPlot[1])

alertcondition(alertCrossWilliamsLongStop, title="Crossed Williams Long Stop", message="Alert from Williams Fractal Trailing Stops: \n {{ticker}} price crossed long stop")
alertcondition(alertCrossWilliamsShortStop, title="Crossed Williams Short Stop", message="Alert from Williams Fractal Trailing Stops: \n {{ticker}} price crossed short stop")

alertcondition(isWilliamsHigh, title="High Printed", message="Alert from Williams Fractal Trailing Stops: \n {{ticker}} Williams High has been confirmed")
alertcondition(isWilliamsLow, title="Low Printed", message="Alert from Williams Fractal Trailing Stops: \n {{ticker}} Williams Low has been confirmed")


// ================================ //
//                                  //
//   (╯°□°)╯︵ sʞloɟ `llɐ s,ʇɐɥ┴   //
//                                  //
// ================================ //
check the below. pls test it.

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © SimpleCryptoLife
#study(title="Williams Fractal Trailing Stops", shorttitle="Williams Trailing Stops", overlay=true
# Converted by Sam4Cok@Samer800    - 04/2024

#Hint ShowWilliamsFractals: Displays little triangles above/below each Williams fractal.
#Hint ShowWilliamsTrailingStop: Displays a trailing stop based on the most recent fractal.
#Hint WilliamsFractalRangeBack: How many bars back to measure for the range. Traditionally, two bars back and two bars forward are used.
#Hint WilliamsFractalRangeForward: How many bars forwards to measure for the range. Traditionally,an equal number of bars two bars back and two bars forward are used.
#Hint WilliamsStopBufferPercentage: Adds a buffer between the actual fractal price and the trail, as a percentage of the fractal price.
#Hint FlipTrailOn: Defines which measurement of the candle (high/low, or close) must exceed the trail for it to flip.
input showBubbles = yes;
input ShowWilliamsFractals = yes;         # "Show All Williams Fractals"
input ShowWilliamsTrailingStop = yes;     # "Show Williams Trailing Stop"
input WilliamsFractalRangeBack = 2;       # "Williams Fractal Range Back"
input WilliamsFractalRangeForward = 2;    # "Williams Fractal Range Forwards"
input WilliamsStopBufferPercentage = 0.0; # "Buffer for Williams Stops %"
input FlipTrailOn = {default "Close", "Wick"}; # "Flip Trail on:"

def na = Double.NaN;

script f_IsWilliamsFractal {
    input _williamsLeftRange = 2;
    input _williamsRightRange = 2;
    input _type = 1;
    def _isWilliamsFractal = (_type == 1 and high[_williamsRightRange] >= Highest(high, _williamsLeftRange + _williamsRightRange + 1))
                          or (_type == -1 and low[_williamsRightRange] <= Lowest(low, _williamsLeftRange + _williamsRightRange + 1));
    def _fractalValue = if _isWilliamsFractal and _type == 1 then high[_williamsRightRange] else
                        if _isWilliamsFractal and _type == -1 then low[_williamsRightRange] else Double.NaN;
    plot fractal = if isNaN(_isWilliamsFractal) then 0 else _isWilliamsFractal;
    plot value   = if isNaN(_fractalValue) then 0 else _fractalValue;
}
script f_addPercentBuffer {
    input _input = close;
    input _buffer = 0;
    input _direction = 1;
    def buffer = if _direction == 1 then _input * (1 + (_buffer / 100)) else
                                         _input * (1 - (_buffer / 100));
    plot out = buffer;
}
script f_persistAndReset {
    input _trigger = yes;
    input _source = close;
    def _output = if _trigger then _source else If(IsNaN(_output[1]), no, _output[1]);
    plot out = _output;
}
script f_trail {
    input _source = close;
    input _trail = close;
    input _direction = 1;
    def f_trail = if _direction == -1 and _source >= _trail[1] then _trail else
                  if _direction == 1 and _source <= _trail[1] then _trail else _source;
    plot out = f_trail;
}
#// Check if current bar confirms a Williams High or Low
def isWilliamsHigh1   = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).fractal;
def williamsHighPrice = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).value;
def isWilliamsLow1    = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).fractal;
def williamsLowPrice  = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).value;

def isWilliamsHigh = if isWilliamsHigh[1] then no else isWilliamsHigh1;
def isWilliamsLow = if isWilliamsLow[1] then no else isWilliamsLow1;

#// Plot the fractal shapes. They need to be offset backwards so they appear over the correct bar.
def williamsOffset = 0 - WilliamsFractalRangeForward;
def isWilliamsHi = isWilliamsHigh[williamsOffset];
def isWilliamsLo = isWilliamsLow[williamsOffset];

plot williamsHi = if (isWilliamsHi and ShowWilliamsFractals) then high else na;
plot williamsLo = if (isWilliamsLo and ShowWilliamsFractals) then low else na;
williamsHi.SetDefaultColor(Color.WHITE);
williamsLo.SetDefaultColor(Color.WHITE);
williamsHi.SetPaintingStrategy(PaintingStrategy.SQUARES);
williamsLo.SetPaintingStrategy(PaintingStrategy.TRIANGLES);

#--WILLIAMS PRICE FRACTALS: CALCULATE AND PLOT TRAILING STOP LINES
def williamsLowPriceBuffered = f_addPercentBuffer(williamsLowPrice, WilliamsStopBufferPercentage, -1);
def williamsHighPriceBuffered = f_addPercentBuffer(williamsHighPrice, WilliamsStopBufferPercentage, 1);
#// Persist the buffered stop price and reset it each time there is a new fractal
def williamsLongStopPrice1 = f_persistAndReset(isWilliamsLow, williamsLowPriceBuffered);
def williamsShortStopPrice1 = f_persistAndReset(isWilliamsHigh, williamsHighPriceBuffered);
#// Trail the high (short) stop down and the low (long) stop up
def williamsLongStopPriceTrail1;def williamsShortStopPriceTrail1;
def williamsShortStopPriceTrail = f_trail(williamsShortStopPrice1, williamsShortStopPriceTrail1[1], -1);
def williamsLongStopPriceTrail = f_trail(williamsLongStopPrice1, williamsLongStopPriceTrail1[1], 1);

script f_flip {
input _flipInput = "Close";
input _longTrail = high;
input _shortTrail = low;
input _longReset = high;
input _shortReset = low;
    def bar = barNumber();
    def _isLong; # = true
    def _isShort; # = true
    def _flipLongSource = if _flipInput == "Close" then close else high; # : na
    def _flipShortSource = if _flipInput == "Close" then close else low; # : na
    def _flipLongNow1 = if bar < 1 then yes else _isShort[1] and _flipLongSource > _shortTrail; # ? true : false
    def _flipShortNow1 = if bar < 1 then yes else _isLong[1] and _flipShortSource < _longTrail; # ? true : false
    def _flipLongNow = if _flipShortNow1 and _flipLongNow1 and close > _longTrail then yes else
                       if _flipShortNow1 and _flipLongNow1 and close <= _longTrail then no else _flipLongNow1;
    def _flipShortNow = if _flipLongNow and _flipShortNow1 and close < _shortTrail then yes else
                        if _flipShortNow1 and _flipLongNow and close >= _shortTrail then no else _flipShortNow1;
    _isLong = if _flipLongNow then yes else if _flipShortNow then no else
              if isNaN(_isLong[1]) then yes else _isLong[1];
    _isShort = if _flipShortNow then yes else if _flipLongNow then no else
               if isNaN(_isShort[1]) then yes else _isShort[1];
#    _longTrailOutput = _longTrail
#    _shortTrailOutput = _shortTrail
    def _longTrailOutput = if _isLong and !_isLong[1] then _longReset else _longTrail; # _longTrailOutput
    def _shortTrailOutput = if _isShort and !_isShort[1] then _shortReset else _shortTrail; # _shortTrailOutput
    def _longTrailPlot = if _isLong then _longTrailOutput else
                         if _isLong and _isShort then _longTrailOutput else Double.NaN;
    def _shortTrailPlot = if _isShort then _shortTrailOutput else
                          if _isLong and _isShort then _shortTrailOutput else Double.NaN;
    plot longTrail = _longTrailOutput;
    plot shortTrail = _shortTrailOutput;
    plot longPlot = _longTrailPlot;
    plot shortPlot = _shortTrailPlot;
}
Script f_getFlipResetWilliamsLong {
input _buffer = 0;
input _isWilliamsLow = yes;
input _williamsRightRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsLow = if isNaN(_isWilliamsLow) then 0 else _isWilliamsLow;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsLow then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsRightRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _lowestLow = fold i = 0 to cnt with p = low do
                     Min(GetValue(low, i), p);
    def _lowestLowAdjusted = _lowestLow * (1 - (_buffer / 100));
    plot out = if _buffer == 0 then _lowestLow else _lowestLowAdjusted;
}
Script f_getFlipResetWilliamsShort {
input _buffer = 0;
input _isWilliamsHigh = yes;
input _williamsLeftRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsHigh = if isNaN(_isWilliamsHigh) then 0 else _isWilliamsHigh;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsHigh then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsLeftRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _highestHigh = fold i = 0 to cnt with p = high do
                       Max(GetValue(high, i), p);
    def _highestHighAdjusted = _highestHigh * (1 + (_buffer / 100));
    plot out = if _buffer == 0 then _highestHigh else _highestHighAdjusted;
}
#// Get the long/short stop price to reset to.
def williamsLongStopPrice2 = f_getFlipResetWilliamsLong(WilliamsStopBufferPercentage, isWilliamsLow, WilliamsFractalRangeForward);
def williamsShortStopPrice2 = f_getFlipResetWilliamsShort(WilliamsStopBufferPercentage, isWilliamsHigh, WilliamsFractalRangeForward);
def williamsLongStopPrice = if isNaN(williamsLongStopPrice2) then williamsShortStopPrice1 else williamsLongStopPrice2;
def williamsShortStopPrice = if isNaN(williamsShortStopPrice2) then williamsShortStopPrice1 else williamsShortStopPrice2;

#/ Get the plots for the trails, to show only long stop when long and short stop when short.
def williamsLongStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longTrail;
def williamsShortStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortTrail;
def williamsLongStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longPlot;
def williamsShortStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortPlot;
#// Have to have these variables back in the global scope so we can persist them and use them as inputs to the function next bar.
#// I don't think there's a way round this because assigning multiple mutable variables via a function doesn't seem to work.
    williamsLongStopPriceTrail1 = williamsLongStopPriceTrailTemp;
    williamsShortStopPriceTrail1 = williamsShortStopPriceTrailTemp;

#// Hide trailing stop plots if the user selected that (input bool inputShowWilliamsStops)
def williamsShortStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsShortStopPriceTrailPlot else na;
def williamsLongStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsLongStopPriceTrailPlot else na;

plot wHi0 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wHi1 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wLo0 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;
plot wLo1 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;

wHi1.SetLineWeight(3);
wLo1.SetLineWeight(3);
wHi0.SetDefaultColor(Color.MAGENTA);
wHi1.SetDefaultColor(Color.PLUM);
wLo0.SetDefaultColor(Color.CYAN);
wLo1.SetDefaultColor(Color.VIOLET);


plot alertCrossWilliamsLongStop = if isNaN(williamsLongStopPriceTrailPlot) and !isNaN(williamsLongStopPriceTrailPlot[1])
                                  then wHi0 else na;
plot alertCrossWilliamsShortStop = if isNaN(williamsShortStopPriceTrailPlot) and !isNaN(williamsShortStopPriceTrailPlot[1])
                                  then wLo0 else na;
alertCrossWilliamsLongStop.SetLineWeight(3);
alertCrossWilliamsShortStop.SetLineWeight(3);
alertCrossWilliamsLongStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsShortStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsLongStop.SetDefaultColor(Color.MAGENTA);
alertCrossWilliamsShortStop.SetDefaultColor(Color.CYAN);

AddChartBubble(showBubbles and alertCrossWilliamsShortStop, wLo0, "Long", Color.CYAN, no);
AddChartBubble(showBubbles and alertCrossWilliamsLongStop, wHi0, "Short", Color.MAGENTA);

#-- END of CODE
 
check the below. pls test it.

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © SimpleCryptoLife
#study(title="Williams Fractal Trailing Stops", shorttitle="Williams Trailing Stops", overlay=true
# Converted by Sam4Cok@Samer800    - 04/2024

#Hint ShowWilliamsFractals: Displays little triangles above/below each Williams fractal.
#Hint ShowWilliamsTrailingStop: Displays a trailing stop based on the most recent fractal.
#Hint WilliamsFractalRangeBack: How many bars back to measure for the range. Traditionally, two bars back and two bars forward are used.
#Hint WilliamsFractalRangeForward: How many bars forwards to measure for the range. Traditionally,an equal number of bars two bars back and two bars forward are used.
#Hint WilliamsStopBufferPercentage: Adds a buffer between the actual fractal price and the trail, as a percentage of the fractal price.
#Hint FlipTrailOn: Defines which measurement of the candle (high/low, or close) must exceed the trail for it to flip.
input showBubbles = yes;
input ShowWilliamsFractals = yes;         # "Show All Williams Fractals"
input ShowWilliamsTrailingStop = yes;     # "Show Williams Trailing Stop"
input WilliamsFractalRangeBack = 2;       # "Williams Fractal Range Back"
input WilliamsFractalRangeForward = 2;    # "Williams Fractal Range Forwards"
input WilliamsStopBufferPercentage = 0.0; # "Buffer for Williams Stops %"
input FlipTrailOn = {default "Close", "Wick"}; # "Flip Trail on:"

def na = Double.NaN;

script f_IsWilliamsFractal {
    input _williamsLeftRange = 2;
    input _williamsRightRange = 2;
    input _type = 1;
    def _isWilliamsFractal = (_type == 1 and high[_williamsRightRange] >= Highest(high, _williamsLeftRange + _williamsRightRange + 1))
                          or (_type == -1 and low[_williamsRightRange] <= Lowest(low, _williamsLeftRange + _williamsRightRange + 1));
    def _fractalValue = if _isWilliamsFractal and _type == 1 then high[_williamsRightRange] else
                        if _isWilliamsFractal and _type == -1 then low[_williamsRightRange] else Double.NaN;
    plot fractal = if isNaN(_isWilliamsFractal) then 0 else _isWilliamsFractal;
    plot value   = if isNaN(_fractalValue) then 0 else _fractalValue;
}
script f_addPercentBuffer {
    input _input = close;
    input _buffer = 0;
    input _direction = 1;
    def buffer = if _direction == 1 then _input * (1 + (_buffer / 100)) else
                                         _input * (1 - (_buffer / 100));
    plot out = buffer;
}
script f_persistAndReset {
    input _trigger = yes;
    input _source = close;
    def _output = if _trigger then _source else If(IsNaN(_output[1]), no, _output[1]);
    plot out = _output;
}
script f_trail {
    input _source = close;
    input _trail = close;
    input _direction = 1;
    def f_trail = if _direction == -1 and _source >= _trail[1] then _trail else
                  if _direction == 1 and _source <= _trail[1] then _trail else _source;
    plot out = f_trail;
}
#// Check if current bar confirms a Williams High or Low
def isWilliamsHigh1   = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).fractal;
def williamsHighPrice = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).value;
def isWilliamsLow1    = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).fractal;
def williamsLowPrice  = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).value;

def isWilliamsHigh = if isWilliamsHigh[1] then no else isWilliamsHigh1;
def isWilliamsLow = if isWilliamsLow[1] then no else isWilliamsLow1;

#// Plot the fractal shapes. They need to be offset backwards so they appear over the correct bar.
def williamsOffset = 0 - WilliamsFractalRangeForward;
def isWilliamsHi = isWilliamsHigh[williamsOffset];
def isWilliamsLo = isWilliamsLow[williamsOffset];

plot williamsHi = if (isWilliamsHi and ShowWilliamsFractals) then high else na;
plot williamsLo = if (isWilliamsLo and ShowWilliamsFractals) then low else na;
williamsHi.SetDefaultColor(Color.WHITE);
williamsLo.SetDefaultColor(Color.WHITE);
williamsHi.SetPaintingStrategy(PaintingStrategy.SQUARES);
williamsLo.SetPaintingStrategy(PaintingStrategy.TRIANGLES);

#--WILLIAMS PRICE FRACTALS: CALCULATE AND PLOT TRAILING STOP LINES
def williamsLowPriceBuffered = f_addPercentBuffer(williamsLowPrice, WilliamsStopBufferPercentage, -1);
def williamsHighPriceBuffered = f_addPercentBuffer(williamsHighPrice, WilliamsStopBufferPercentage, 1);
#// Persist the buffered stop price and reset it each time there is a new fractal
def williamsLongStopPrice1 = f_persistAndReset(isWilliamsLow, williamsLowPriceBuffered);
def williamsShortStopPrice1 = f_persistAndReset(isWilliamsHigh, williamsHighPriceBuffered);
#// Trail the high (short) stop down and the low (long) stop up
def williamsLongStopPriceTrail1;def williamsShortStopPriceTrail1;
def williamsShortStopPriceTrail = f_trail(williamsShortStopPrice1, williamsShortStopPriceTrail1[1], -1);
def williamsLongStopPriceTrail = f_trail(williamsLongStopPrice1, williamsLongStopPriceTrail1[1], 1);

script f_flip {
input _flipInput = "Close";
input _longTrail = high;
input _shortTrail = low;
input _longReset = high;
input _shortReset = low;
    def bar = barNumber();
    def _isLong; # = true
    def _isShort; # = true
    def _flipLongSource = if _flipInput == "Close" then close else high; # : na
    def _flipShortSource = if _flipInput == "Close" then close else low; # : na
    def _flipLongNow1 = if bar < 1 then yes else _isShort[1] and _flipLongSource > _shortTrail; # ? true : false
    def _flipShortNow1 = if bar < 1 then yes else _isLong[1] and _flipShortSource < _longTrail; # ? true : false
    def _flipLongNow = if _flipShortNow1 and _flipLongNow1 and close > _longTrail then yes else
                       if _flipShortNow1 and _flipLongNow1 and close <= _longTrail then no else _flipLongNow1;
    def _flipShortNow = if _flipLongNow and _flipShortNow1 and close < _shortTrail then yes else
                        if _flipShortNow1 and _flipLongNow and close >= _shortTrail then no else _flipShortNow1;
    _isLong = if _flipLongNow then yes else if _flipShortNow then no else
              if isNaN(_isLong[1]) then yes else _isLong[1];
    _isShort = if _flipShortNow then yes else if _flipLongNow then no else
               if isNaN(_isShort[1]) then yes else _isShort[1];
#    _longTrailOutput = _longTrail
#    _shortTrailOutput = _shortTrail
    def _longTrailOutput = if _isLong and !_isLong[1] then _longReset else _longTrail; # _longTrailOutput
    def _shortTrailOutput = if _isShort and !_isShort[1] then _shortReset else _shortTrail; # _shortTrailOutput
    def _longTrailPlot = if _isLong then _longTrailOutput else
                         if _isLong and _isShort then _longTrailOutput else Double.NaN;
    def _shortTrailPlot = if _isShort then _shortTrailOutput else
                          if _isLong and _isShort then _shortTrailOutput else Double.NaN;
    plot longTrail = _longTrailOutput;
    plot shortTrail = _shortTrailOutput;
    plot longPlot = _longTrailPlot;
    plot shortPlot = _shortTrailPlot;
}
Script f_getFlipResetWilliamsLong {
input _buffer = 0;
input _isWilliamsLow = yes;
input _williamsRightRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsLow = if isNaN(_isWilliamsLow) then 0 else _isWilliamsLow;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsLow then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsRightRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _lowestLow = fold i = 0 to cnt with p = low do
                     Min(GetValue(low, i), p);
    def _lowestLowAdjusted = _lowestLow * (1 - (_buffer / 100));
    plot out = if _buffer == 0 then _lowestLow else _lowestLowAdjusted;
}
Script f_getFlipResetWilliamsShort {
input _buffer = 0;
input _isWilliamsHigh = yes;
input _williamsLeftRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsHigh = if isNaN(_isWilliamsHigh) then 0 else _isWilliamsHigh;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsHigh then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsLeftRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _highestHigh = fold i = 0 to cnt with p = high do
                       Max(GetValue(high, i), p);
    def _highestHighAdjusted = _highestHigh * (1 + (_buffer / 100));
    plot out = if _buffer == 0 then _highestHigh else _highestHighAdjusted;
}
#// Get the long/short stop price to reset to.
def williamsLongStopPrice2 = f_getFlipResetWilliamsLong(WilliamsStopBufferPercentage, isWilliamsLow, WilliamsFractalRangeForward);
def williamsShortStopPrice2 = f_getFlipResetWilliamsShort(WilliamsStopBufferPercentage, isWilliamsHigh, WilliamsFractalRangeForward);
def williamsLongStopPrice = if isNaN(williamsLongStopPrice2) then williamsShortStopPrice1 else williamsLongStopPrice2;
def williamsShortStopPrice = if isNaN(williamsShortStopPrice2) then williamsShortStopPrice1 else williamsShortStopPrice2;

#/ Get the plots for the trails, to show only long stop when long and short stop when short.
def williamsLongStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longTrail;
def williamsShortStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortTrail;
def williamsLongStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longPlot;
def williamsShortStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortPlot;
#// Have to have these variables back in the global scope so we can persist them and use them as inputs to the function next bar.
#// I don't think there's a way round this because assigning multiple mutable variables via a function doesn't seem to work.
    williamsLongStopPriceTrail1 = williamsLongStopPriceTrailTemp;
    williamsShortStopPriceTrail1 = williamsShortStopPriceTrailTemp;

#// Hide trailing stop plots if the user selected that (input bool inputShowWilliamsStops)
def williamsShortStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsShortStopPriceTrailPlot else na;
def williamsLongStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsLongStopPriceTrailPlot else na;

plot wHi0 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wHi1 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wLo0 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;
plot wLo1 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;

wHi1.SetLineWeight(3);
wLo1.SetLineWeight(3);
wHi0.SetDefaultColor(Color.MAGENTA);
wHi1.SetDefaultColor(Color.PLUM);
wLo0.SetDefaultColor(Color.CYAN);
wLo1.SetDefaultColor(Color.VIOLET);


plot alertCrossWilliamsLongStop = if isNaN(williamsLongStopPriceTrailPlot) and !isNaN(williamsLongStopPriceTrailPlot[1])
                                  then wHi0 else na;
plot alertCrossWilliamsShortStop = if isNaN(williamsShortStopPriceTrailPlot) and !isNaN(williamsShortStopPriceTrailPlot[1])
                                  then wLo0 else na;
alertCrossWilliamsLongStop.SetLineWeight(3);
alertCrossWilliamsShortStop.SetLineWeight(3);
alertCrossWilliamsLongStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsShortStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsLongStop.SetDefaultColor(Color.MAGENTA);
alertCrossWilliamsShortStop.SetDefaultColor(Color.CYAN);

AddChartBubble(showBubbles and alertCrossWilliamsShortStop, wLo0, "Long", Color.CYAN, no);
AddChartBubble(showBubbles and alertCrossWilliamsLongStop, wHi0, "Short", Color.MAGENTA);

#-- END of CODE
Nice - I like this although I modified it to only show the bubbles for me and omitted the lines.
 
check the below. pls test it.

CSS:
#// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
#// © SimpleCryptoLife
#study(title="Williams Fractal Trailing Stops", shorttitle="Williams Trailing Stops", overlay=true
# Converted by Sam4Cok@Samer800    - 04/2024

#Hint ShowWilliamsFractals: Displays little triangles above/below each Williams fractal.
#Hint ShowWilliamsTrailingStop: Displays a trailing stop based on the most recent fractal.
#Hint WilliamsFractalRangeBack: How many bars back to measure for the range. Traditionally, two bars back and two bars forward are used.
#Hint WilliamsFractalRangeForward: How many bars forwards to measure for the range. Traditionally,an equal number of bars two bars back and two bars forward are used.
#Hint WilliamsStopBufferPercentage: Adds a buffer between the actual fractal price and the trail, as a percentage of the fractal price.
#Hint FlipTrailOn: Defines which measurement of the candle (high/low, or close) must exceed the trail for it to flip.
input showBubbles = yes;
input ShowWilliamsFractals = yes;         # "Show All Williams Fractals"
input ShowWilliamsTrailingStop = yes;     # "Show Williams Trailing Stop"
input WilliamsFractalRangeBack = 2;       # "Williams Fractal Range Back"
input WilliamsFractalRangeForward = 2;    # "Williams Fractal Range Forwards"
input WilliamsStopBufferPercentage = 0.0; # "Buffer for Williams Stops %"
input FlipTrailOn = {default "Close", "Wick"}; # "Flip Trail on:"

def na = Double.NaN;

script f_IsWilliamsFractal {
    input _williamsLeftRange = 2;
    input _williamsRightRange = 2;
    input _type = 1;
    def _isWilliamsFractal = (_type == 1 and high[_williamsRightRange] >= Highest(high, _williamsLeftRange + _williamsRightRange + 1))
                          or (_type == -1 and low[_williamsRightRange] <= Lowest(low, _williamsLeftRange + _williamsRightRange + 1));
    def _fractalValue = if _isWilliamsFractal and _type == 1 then high[_williamsRightRange] else
                        if _isWilliamsFractal and _type == -1 then low[_williamsRightRange] else Double.NaN;
    plot fractal = if isNaN(_isWilliamsFractal) then 0 else _isWilliamsFractal;
    plot value   = if isNaN(_fractalValue) then 0 else _fractalValue;
}
script f_addPercentBuffer {
    input _input = close;
    input _buffer = 0;
    input _direction = 1;
    def buffer = if _direction == 1 then _input * (1 + (_buffer / 100)) else
                                         _input * (1 - (_buffer / 100));
    plot out = buffer;
}
script f_persistAndReset {
    input _trigger = yes;
    input _source = close;
    def _output = if _trigger then _source else If(IsNaN(_output[1]), no, _output[1]);
    plot out = _output;
}
script f_trail {
    input _source = close;
    input _trail = close;
    input _direction = 1;
    def f_trail = if _direction == -1 and _source >= _trail[1] then _trail else
                  if _direction == 1 and _source <= _trail[1] then _trail else _source;
    plot out = f_trail;
}
#// Check if current bar confirms a Williams High or Low
def isWilliamsHigh1   = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).fractal;
def williamsHighPrice = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, 1).value;
def isWilliamsLow1    = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).fractal;
def williamsLowPrice  = f_IsWilliamsFractal(WilliamsFractalRangeBack, WilliamsFractalRangeForward, -1).value;

def isWilliamsHigh = if isWilliamsHigh[1] then no else isWilliamsHigh1;
def isWilliamsLow = if isWilliamsLow[1] then no else isWilliamsLow1;

#// Plot the fractal shapes. They need to be offset backwards so they appear over the correct bar.
def williamsOffset = 0 - WilliamsFractalRangeForward;
def isWilliamsHi = isWilliamsHigh[williamsOffset];
def isWilliamsLo = isWilliamsLow[williamsOffset];

plot williamsHi = if (isWilliamsHi and ShowWilliamsFractals) then high else na;
plot williamsLo = if (isWilliamsLo and ShowWilliamsFractals) then low else na;
williamsHi.SetDefaultColor(Color.WHITE);
williamsLo.SetDefaultColor(Color.WHITE);
williamsHi.SetPaintingStrategy(PaintingStrategy.SQUARES);
williamsLo.SetPaintingStrategy(PaintingStrategy.TRIANGLES);

#--WILLIAMS PRICE FRACTALS: CALCULATE AND PLOT TRAILING STOP LINES
def williamsLowPriceBuffered = f_addPercentBuffer(williamsLowPrice, WilliamsStopBufferPercentage, -1);
def williamsHighPriceBuffered = f_addPercentBuffer(williamsHighPrice, WilliamsStopBufferPercentage, 1);
#// Persist the buffered stop price and reset it each time there is a new fractal
def williamsLongStopPrice1 = f_persistAndReset(isWilliamsLow, williamsLowPriceBuffered);
def williamsShortStopPrice1 = f_persistAndReset(isWilliamsHigh, williamsHighPriceBuffered);
#// Trail the high (short) stop down and the low (long) stop up
def williamsLongStopPriceTrail1;def williamsShortStopPriceTrail1;
def williamsShortStopPriceTrail = f_trail(williamsShortStopPrice1, williamsShortStopPriceTrail1[1], -1);
def williamsLongStopPriceTrail = f_trail(williamsLongStopPrice1, williamsLongStopPriceTrail1[1], 1);

script f_flip {
input _flipInput = "Close";
input _longTrail = high;
input _shortTrail = low;
input _longReset = high;
input _shortReset = low;
    def bar = barNumber();
    def _isLong; # = true
    def _isShort; # = true
    def _flipLongSource = if _flipInput == "Close" then close else high; # : na
    def _flipShortSource = if _flipInput == "Close" then close else low; # : na
    def _flipLongNow1 = if bar < 1 then yes else _isShort[1] and _flipLongSource > _shortTrail; # ? true : false
    def _flipShortNow1 = if bar < 1 then yes else _isLong[1] and _flipShortSource < _longTrail; # ? true : false
    def _flipLongNow = if _flipShortNow1 and _flipLongNow1 and close > _longTrail then yes else
                       if _flipShortNow1 and _flipLongNow1 and close <= _longTrail then no else _flipLongNow1;
    def _flipShortNow = if _flipLongNow and _flipShortNow1 and close < _shortTrail then yes else
                        if _flipShortNow1 and _flipLongNow and close >= _shortTrail then no else _flipShortNow1;
    _isLong = if _flipLongNow then yes else if _flipShortNow then no else
              if isNaN(_isLong[1]) then yes else _isLong[1];
    _isShort = if _flipShortNow then yes else if _flipLongNow then no else
               if isNaN(_isShort[1]) then yes else _isShort[1];
#    _longTrailOutput = _longTrail
#    _shortTrailOutput = _shortTrail
    def _longTrailOutput = if _isLong and !_isLong[1] then _longReset else _longTrail; # _longTrailOutput
    def _shortTrailOutput = if _isShort and !_isShort[1] then _shortReset else _shortTrail; # _shortTrailOutput
    def _longTrailPlot = if _isLong then _longTrailOutput else
                         if _isLong and _isShort then _longTrailOutput else Double.NaN;
    def _shortTrailPlot = if _isShort then _shortTrailOutput else
                          if _isLong and _isShort then _shortTrailOutput else Double.NaN;
    plot longTrail = _longTrailOutput;
    plot shortTrail = _shortTrailOutput;
    plot longPlot = _longTrailPlot;
    plot shortPlot = _shortTrailPlot;
}
Script f_getFlipResetWilliamsLong {
input _buffer = 0;
input _isWilliamsLow = yes;
input _williamsRightRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsLow = if isNaN(_isWilliamsLow) then 0 else _isWilliamsLow;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsLow then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsRightRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _lowestLow = fold i = 0 to cnt with p = low do
                     Min(GetValue(low, i), p);
    def _lowestLowAdjusted = _lowestLow * (1 - (_buffer / 100));
    plot out = if _buffer == 0 then _lowestLow else _lowestLowAdjusted;
}
Script f_getFlipResetWilliamsShort {
input _buffer = 0;
input _isWilliamsHigh = yes;
input _williamsLeftRange = 2;
    def n = if !isNaN(close) then BarNumber() else n[1];
    def bar = if n < 0 then 0 else  n;
    def isWilliamsHigh = if isNaN(_isWilliamsHigh) then 0 else _isWilliamsHigh;
    def _barIndexWhenLastFractalConfirmed = if isWilliamsHigh then bar else _barIndexWhenLastFractalConfirmed[1];
    def _barsSinceLastFractalConfirmed = bar - _barIndexWhenLastFractalConfirmed;
    def _barsToGoBack = floor(_barsSinceLastFractalConfirmed + _williamsLeftRange);
    def cnt = if (isNaN(_barsToGoBack) or _barsToGoBack < 0) then 0 else _barsToGoBack;
    def _highestHigh = fold i = 0 to cnt with p = high do
                       Max(GetValue(high, i), p);
    def _highestHighAdjusted = _highestHigh * (1 + (_buffer / 100));
    plot out = if _buffer == 0 then _highestHigh else _highestHighAdjusted;
}
#// Get the long/short stop price to reset to.
def williamsLongStopPrice2 = f_getFlipResetWilliamsLong(WilliamsStopBufferPercentage, isWilliamsLow, WilliamsFractalRangeForward);
def williamsShortStopPrice2 = f_getFlipResetWilliamsShort(WilliamsStopBufferPercentage, isWilliamsHigh, WilliamsFractalRangeForward);
def williamsLongStopPrice = if isNaN(williamsLongStopPrice2) then williamsShortStopPrice1 else williamsLongStopPrice2;
def williamsShortStopPrice = if isNaN(williamsShortStopPrice2) then williamsShortStopPrice1 else williamsShortStopPrice2;

#/ Get the plots for the trails, to show only long stop when long and short stop when short.
def williamsLongStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longTrail;
def williamsShortStopPriceTrailTemp =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortTrail;
def williamsLongStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).longPlot;
def williamsShortStopPriceTrailPlot =
  f_flip(FlipTrailOn, williamsLongStopPriceTrail,williamsShortStopPriceTrail,williamsLongStopPrice, williamsShortStopPrice).shortPlot;
#// Have to have these variables back in the global scope so we can persist them and use them as inputs to the function next bar.
#// I don't think there's a way round this because assigning multiple mutable variables via a function doesn't seem to work.
    williamsLongStopPriceTrail1 = williamsLongStopPriceTrailTemp;
    williamsShortStopPriceTrail1 = williamsShortStopPriceTrailTemp;

#// Hide trailing stop plots if the user selected that (input bool inputShowWilliamsStops)
def williamsShortStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsShortStopPriceTrailPlot else na;
def williamsLongStopPriceTrailPlotDisplay = if ShowWilliamsTrailingStop then williamsLongStopPriceTrailPlot else na;

plot wHi0 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wHi1 = if williamsShortStopPriceTrailPlotDisplay then williamsShortStopPriceTrailPlotDisplay else na;
plot wLo0 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;
plot wLo1 = if williamsLongStopPriceTrailPlotDisplay then williamsLongStopPriceTrailPlotDisplay else na;

wHi1.SetLineWeight(3);
wLo1.SetLineWeight(3);
wHi0.SetDefaultColor(Color.MAGENTA);
wHi1.SetDefaultColor(Color.PLUM);
wLo0.SetDefaultColor(Color.CYAN);
wLo1.SetDefaultColor(Color.VIOLET);


plot alertCrossWilliamsLongStop = if isNaN(williamsLongStopPriceTrailPlot) and !isNaN(williamsLongStopPriceTrailPlot[1])
                                  then wHi0 else na;
plot alertCrossWilliamsShortStop = if isNaN(williamsShortStopPriceTrailPlot) and !isNaN(williamsShortStopPriceTrailPlot[1])
                                  then wLo0 else na;
alertCrossWilliamsLongStop.SetLineWeight(3);
alertCrossWilliamsShortStop.SetLineWeight(3);
alertCrossWilliamsLongStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsShortStop.SetPaintingStrategy(PaintingStrategy.POINTS);
alertCrossWilliamsLongStop.SetDefaultColor(Color.MAGENTA);
alertCrossWilliamsShortStop.SetDefaultColor(Color.CYAN);

AddChartBubble(showBubbles and alertCrossWilliamsShortStop, wLo0, "Long", Color.CYAN, no);
AddChartBubble(showBubbles and alertCrossWilliamsLongStop, wHi0, "Short", Color.MAGENTA);

#-- END of CODE
@samer800 you did it a great job!! one question its possible to add a color candles with the signal, meaning if is a short to paint the candles magenta, if is long to paint the candles cyan otherwise candles gray. thank you in advance!
 
Is there a way to get a scan version for this indicator?, when i try it, it does not allow me to run a scan
 
Is there a way to get a scan version for this indicator?, when i try it, it does not allow me to run a scan

Unfortunately, this script is too complex.
No, this indicator cannot be used in Scans, Watchlists, Conditional Orders or any other ToS widget.
JOnLkfu.png


While no script is "too complex" to plot on the chart; Schwab does throttle the use of complex scripts in scans, watchlists, and conditional orders to prevent high load runs on its servers.
 
I am trying to make a modification to this code so that the stop line only moves when some other condition is also true. But I can't seem to get it to work. I modified the lines that call f_trail so that it is only called when my condition (MoveTrailLine) is true and otherwise just uses the last price trail as follows

OLD LINES
#def williamsShortStopPriceTrail = f_trail(williamsShortStopPrice1, williamsShortStopPriceTrail1[1], -1);
#def williamsLongStopPriceTrail = f_trail(williamsLongStopPrice1, williamsLongStopPriceTrail1[1], 1);

NEW LINES
def williamsShortStopPriceTrail = if MoveTrailLine then f_trail(williamsShortStopPrice1, williamsShortStopPriceTrail1[1], -1) else williamsShortStopPriceTrail[1];
def williamsLongStopPriceTrail = if MoveTrailLine then f_trail(williamsLongStopPrice1, williamsLongStopPriceTrail1[1], 1) else williamsLongStopPriceTrail[1];

The problem is that I believe the flip occurs based on just the buffered fractals and doesn't use the trail price at all. So this works great to only move the stop line when my condition is true until a flip occurs and then everything goes crazy on the screen because the flip is not respecting the trail price but just the last fractal price. My problem is that I can't not store the last fractal price in the buffer because I need those so that when my condition is true I can use the last fractal found to move the stop line to. So it seems like a catch22 with how the original code was written and this is quite complex code.

So I was hoping that the original author might have some insight as to how I could do this. I will keep working on it but if anyone can help me fast track it I would certainly appreciate it.

Thanks!

Bill
 

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
163 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top