ToS ATR Trailing Stop in ThinkOrSwim

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

Default TOS ATR Trailing Stop code is shown below.

Problem
The indication will change mid-bar as price changes.

Solution
Change the study so that it does not update until AFTER the bar closes/new bar Opens.

Question
How does TOS determine that a new bar has opened?

Code:
#
# TD Ameritrade IP Company, Inc. (c) 2009-2023
#

input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.5;
input firstTrade = {default long, short};
input averageType = AverageType.WILDERS;

Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
    then high - close[1]
    else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
    then close[1] - low
    else (close[1] - low) - 0.5 * (low[1] - high);

def trueRange;
switch (trailType) {
case modified:
    trueRange = Max(HiLo, Max(HRef, LRef));
case unmodified:
    trueRange = TrueRange(high, close, low);
}
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 =  close - loss;
        case short:
            state = state.short;
            trail = close + loss;
        }
    } else {
        state = state.init;
        trail = Double.NaN;
    }
case long:
    if (close > trail[1]) {
        state = state.long;
        trail = Max(trail[1], close - loss);
    } else {
        state = state.short;
        trail = close + loss;
    }
case short:
    if (close < trail[1]) {
        state = state.short;
        trail = Min(trail[1], close + loss);
    } else {
        state = state.long;
        trail =  close - loss;
    }
}

def BuySignal = Crosses(state == state.long, 0, CrossingDirection.ABOVE);
def SellSignal = Crosses(state == state.short, 0, CrossingDirection.ABOVE);

plot TrailingStop = trail;

TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Buy", GetColor(0));
TrailingStop.DefineColor("Sell", GetColor(1));
TrailingStop.AssignValueColor(if state == state.long
    then TrailingStop.Color("Sell")
    else TrailingStop.Color("Buy"));
 
Default TOS ATR Trailing Stop code is shown below.

Problem
The indication will change mid-bar as price changes.

Solution
Change the study so that it does not update until AFTER the bar closes/new bar Opens.

Question
How does TOS determine that a new bar has opened?

Code:
#
# TD Ameritrade IP Company, Inc. (c) 2009-2023
#

input trailType = {default modified, unmodified};
input ATRPeriod = 5;
input ATRFactor = 3.5;
input firstTrade = {default long, short};
input averageType = AverageType.WILDERS;

Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
    then high - close[1]
    else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
    then close[1] - low
    else (close[1] - low) - 0.5 * (low[1] - high);

def trueRange;
switch (trailType) {
case modified:
    trueRange = Max(HiLo, Max(HRef, LRef));
case unmodified:
    trueRange = TrueRange(high, close, low);
}
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 =  close - loss;
        case short:
            state = state.short;
            trail = close + loss;
        }
    } else {
        state = state.init;
        trail = Double.NaN;
    }
case long:
    if (close > trail[1]) {
        state = state.long;
        trail = Max(trail[1], close - loss);
    } else {
        state = state.short;
        trail = close + loss;
    }
case short:
    if (close < trail[1]) {
        state = state.short;
        trail = Min(trail[1], close + loss);
    } else {
        state = state.long;
        trail =  close - loss;
    }
}

def BuySignal = Crosses(state == state.long, 0, CrossingDirection.ABOVE);
def SellSignal = Crosses(state == state.short, 0, CrossingDirection.ABOVE);

plot TrailingStop = trail;

TrailingStop.SetPaintingStrategy(PaintingStrategy.POINTS);
TrailingStop.DefineColor("Buy", GetColor(0));
TrailingStop.DefineColor("Sell", GetColor(1));
TrailingStop.AssignValueColor(if state == state.long
    then TrailingStop.Color("Sell")
    else TrailingStop.Color("Buy"));

is this what you want ?
this will plot the ATR, but not on the current bar

# atr_prev
declare lower;

def na = double.nan;
def bn = barnumber();
def lastbar = !isnan(close[0]) and isnan(close[-1]);

input length = 14;
input averageType = AverageType.WILDERS;
def ATR1 = MovingAverage(averageType, TrueRange(high, close, low), length);

plot atr = if lastbar then na else atr1;
ATR.SetDefaultColor(GetColor(8));
#
 
is this what you want ?
this will plot the ATR, but not on the current bar

# atr_prev
declare lower;

def na = double.nan;
def bn = barnumber();
def lastbar = !isnan(close[0]) and isnan(close[-1]);

input length = 14;
input averageType = AverageType.WILDERS;
def ATR1 = MovingAverage(averageType, TrueRange(high, close, low), length);

plot atr = if lastbar then na else atr1;
ATR.SetDefaultColor(GetColor(8));
#
Thank you. That looks like what I want. I will test on Monday.
 
@SleepyZ

I have a similar question, how would i make the lines stop when a signal changes direction? Because right now the flow buy signal to the next buy signal and sell to the next sell.
 
Trend Chaser Script - ATR Based Indicator For ThinkOrSwim

Code:
# Trend Chaser - (9-16-2023) Creator: Ricky Gaspard

# trendType: The choice between using modified or unmodified True Range depends on the specific trading strategy and the trader's preferences. The modified method may provide smoother values when there are gaps or sudden changes in price, whereas the unmodified method is simpler and more commonly used. In the provided code, you can choose between these two methods using the trendType input parameter.

# ATRPeriod: Traders often experiment with different ATR periods to tailor the indicator to their trading style and the specific assets they are analyzing. A shorter ATR period might be suitable for short-term traders looking for quick signals, while a longer ATR period might be preferred by longer-term investors looking for a more stable assessment of volatility. Changing this will tell the script how many candles you want the script to look back before calculating a decision to plot an arrow. Defaut is 2 ATRPeriod.

# ATRFactor: It's important to note that the ATRFactor parameter is a key part of risk management in trading. By adjusting this factor, traders can control the level of risk they are willing to take on each trade, helping to protect their capital and manage their overall portfolio risk. It's a good practice to test different ATRFactor values and analyze their impact on your trading strategy's performance before using them in live trading. Think of it as a stop loss. Adjusting this will affect arror placement. Changing this to 1 will plot and arrow sooner after a trend reversal is detected. Default is 1.5 ATR.

# WARNING: Just like all indicators, if a stock is channeling, squeezing or consolidating you will get multiple up and down arrows. Wait for a breakout up or down to get the larger trend run. If you are in a trend take profits as the trend takes place. Do not wait on an arrow to sell or cover all held shares.

# Important: If you change the defualt ATRPeriod and ATRFactor you will also need to go into the scan code and change those settings to match.


input trendType = {default modified, unmodified};
input ATRPeriod = 2;
input ATRFactor = 1.5;
input TradeType = {default long, short};
input averageType = AverageType.WILDERS;

Assert(ATRFactor > 0, "'atr factor' must be positive: " + ATRFactor);

def HiLo = Min(high - low, 1.5 * Average(high - low, ATRPeriod));
def HRef = if low <= high[1]
    then high - close[1]
    else (high - close[1]) - 0.5 * (low - high[1]);
def LRef = if high >= low[1]
    then close[1] - low
    else (close[1] - low) - 0.5 * (low[1] - high);

def trueRange;
switch (trendType) {
case modified:
    trueRange = Max(HiLo, Max(HRef, LRef));
case unmodified:
    trueRange = TrueRange(high, close, low);
}
def loss = ATRFactor * MovingAverage(averageType, trueRange, ATRPeriod);

def direction = {default init, long, short};
def trend;
switch (direction[1]) {
case init:
    if (!IsNaN(loss)) {
        switch (TradeType) {
        case long:
            direction = direction.long;
            trend =  close - loss;
        case short:
            direction = direction.short;
            trend = close + loss;
        }
    } else {
        direction = direction.init;
        trend = Double.NaN;
    }
case long:
    if (close > trend[1]) {
        direction = direction.long;
        trend = Max(trend[1], close - loss);
    } else {
        direction = direction.short;
        trend = close + loss;
    }
case short:
    if (close < trend[1]) {
        direction = direction.short;
        trend = Min(trend[1], close + loss);
    } else {
        direction = direction.long;
        trend =  close - loss;
    }
}

def BuySignal = Crosses(direction == direction.long, 0, CrossingDirection.ABOVE);
def SellSignal = Crosses(direction == direction.short, 0, CrossingDirection.ABOVE);

plot ArrowUp = if BuySignal then 1 else 0;
arrowUp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
arrowUp.SetDefaultColor(Color.YELLOW);

plot ArrowDown = if SellSignal then 1 else 0;
arrowDown.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
arrowDown.SetDefaultColor(Color.YELLOW);
 
Last edited by a moderator:

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
346 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