# Original Code From: TD Ameritrade IP Company, Inc. (c) 2009-2020
# Original StudyName: ATRTrailingStop
# Type: Study
# blackFLAG FTS SwingArms
# Edited by: Jose Azcarate
# blackFLAG Futures Trading - FOR EDUCATIONAL PURPOSES ONLY
# TWITTER: @blackflagfuture
# Settings Vary. My preferred setting is 28 / 5 But also use 30 / 8 and 5 / 3.5 depending on strategy.
# 20240806 - Agg period added
input agg = AggregationPeriod.MIN;
input trailType = {default modified, unmodified};
input ATRPeriod = 28;
input ATRFactor = 5;
input firstTrade = {default long, short};
input averageType = AverageType.WILDERS;
input fib1Level = 61.8;
input fib2Level = 78.6;
input fib3Level = 88.6;
Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);
def h = high(period = agg);
def l = low(period = agg);
def o = open(period = agg);
def c = close(period = agg);
def HiLo = Min(h - l, 1.5 * Average(h - l, ATRPeriod));
def HRef = if l <= h[1]
then h - c[1]
else (h - c[1]) - 0.5 * (l - h[1]);
def LRef = if h >= l[1]
then c[1] - l
else (c[1] - l) - 0.5 * (l[1] - h);
def trueRange;
switch (trailType) {
case modified:
trueRange = Max(HiLo, Max(HRef, LRef));
case unmodified:
trueRange = TrueRange(h, c, l);
}
def loss = ATRFactor * MovingAverage(averageType, trueRange, ATRPeriod);
def state = {default init, long, short};
def trail;
switch (state[1]) {
case init:
if (!IsNaN(loss)) {
switch (firstTrade) {
case long:
state = state.long;
trail = c - loss;
case short:
state = state.short;
trail = c + loss;
}
} else {
state = state.init;
trail = Double.NaN;
}
case long:
if (c > trail[1]) {
state = state.long;
trail = Max(trail[1], c - loss);
} else {
state = state.short;
trail = c + loss;
}
case short:
if (c < trail[1]) {
state = state.short;
trail = Min(trail[1], c + loss);
} else {
state = state.long;
trail = c - loss;
}
}
def BuySignal = Crosses(state == state.long, 0, CrossingDirection.ABOVE);
def SellSignal = Crosses(state == state.short, 0, CrossingDirection.ABOVE);
def ex = if BuySignal then h else if SellSignal then l else if state == state.long then Max(ex[1], h) else if state == state.short then Min(ex[1], l) else ex[1];
plot TrailingStop = trail;
TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Long", Color.GREEN);
TrailingStop.DefineColor("Short", Color.RED);
TrailingStop.AssignValueColor(if state == state.long
then TrailingStop.Color("Long")
else TrailingStop.Color("Short"));
plot Extremum = ex;
Extremum.SetPaintingStrategy(PaintingStrategy.POINTS);
Extremum.DefineColor("HH", Color.GREEN);
Extremum.DefineColor("LL", Color.RED);
Extremum.AssignValueColor(if state == state.long
then Extremum.Color("HH")
else Extremum.Color("LL"));
Extremum.Hide();
def f1 = ex + (trail - ex) * fib1Level / 100;
def f2 = ex + (trail - ex) * fib2Level / 100;
def f3 = ex + (trail - ex) * fib3Level / 100;
def l100 = trail + 0;
plot Fib1 = f1;
Fib1.SetPaintingStrategy(PaintingStrategy.POINTS);
Fib1.SetDefaultColor(Color.BLACK);
Fib1.Hide();
plot Fib2 = f2;
Fib2.SetPaintingStrategy(PaintingStrategy.POINTS);
Fib2.SetDefaultColor(Color.BLACK);
Fib2.Hide();
plot Fib3 = f3;
Fib3.SetPaintingStrategy(PaintingStrategy.POINTS);
Fib3.SetDefaultColor(Color.BLACK);
Fib3.Hide();
AddCloud(f1, f2, Color.LIGHT_GREEN, Color.LIGHT_RED, no);
AddCloud(f2, f3, Color.GREEN, Color.RED, no);
AddCloud(f3, l100, Color.DARK_GREEN, Color.DARK_RED, no);
def l1 = state[1] == state.long and c crosses below f1[1];
def l2 = state[1] == state.long and c crosses below f2[1];
def l3 = state[1] == state.long and c crosses below f3[1];
def s1 = state[1] == state.short and c crosses above f1[1];
def s2 = state[1] == state.short and c crosses above f2[1];
def s3 = state[1] == state.short and c crosses above f3[1];
def atr = Average(TrueRange(h, c, l), 14);
plot LS1 = if l1 then l - atr else Double.NaN;
plot LS2 = if l2 then l - 1.5 * atr else Double.NaN;
plot LS3 = if l3 then l - 2 * atr else Double.NaN;
plot SS1 = if s1 then h + atr else Double.NaN;
plot SS2 = if s2 then h + 1.5 * atr else Double.NaN;
plot SS3 = if s3 then h + 2 * atr else Double.NaN;
LS1.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
LS1.SetDefaultColor(Color.GREEN);
LS1.SetLineWeight(1);
LS1.Hide();
LS2.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
LS2.SetDefaultColor(Color.GREEN);
LS2.SetLineWeight(1);
LS2.Hide();
LS3.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
LS3.SetDefaultColor(Color.GREEN);
LS3.SetLineWeight(1);
LS3.Hide();
SS1.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
SS1.SetDefaultColor(Color.RED);
SS1.SetLineWeight(1);
SS1.Hide();
SS2.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
SS2.SetDefaultColor(Color.RED);
SS2.SetLineWeight(1);
SS2.Hide();
SS3.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
SS3.SetDefaultColor(Color.RED);
SS3.SetLineWeight(1);
SS3.Hide();
Alert(l1, "Price crossed below Fib1 level in long trend", Alert.BAR, Sound.Bell);
Alert(l2, "Price crossed below Fib2 level in long trend", Alert.BAR, Sound.Bell);
Alert(l3, "Price crossed below Fib3 level in long trend", Alert.BAR, Sound.Bell);
Alert(s1, "Price crossed above Fib1 level in short trend", Alert.BAR, Sound.Bell);
Alert(s2, "Price crossed above Fib2 level in short trend", Alert.BAR, Sound.Bell);
Alert(s3, "Price crossed above Fib3 level in short trend", Alert.BAR, Sound.Bell);