SLIM Ribbon Indicator for ThinkorSwim

I think i just saw it repaint on me. Trying to wait for another signal to show it.. maybe someone else caught one?
No it doesn't repaint. Signals are set to trigger on the close of the next candle after the buy/sell condition is met. So the buy/sell condition is confirmed first, then the signal fires.
 
The "sell" signal repaints. I saw it do it twice so far.
Thanks for the info. So I can debug further, can you confirm if the repaint behavior occurs before or after the signal candle closes please? i.e. does the sell signal disappear/appear while signal candle is still open or is it changing once the signal candle has closed & subsequent candles have already rendered?
 
So the bar will signal a "close" only after the bar has already started.

So let's say the current bar is open. If the conditions for a "close" are met, it will retroactively signal as if a "close" signal was fired off from the very beginning.
 
So the bar will signal a "close" only after the bar has already started.

So let's say the current bar is open. If the conditions for a "close" are met, it will retroactively signal as if a "close" signal was fired off from the very beginning.
Got it, thanks for the extra info. Would it be possible for you to post a screenshot of the behavior so i can dig into it a bit deeper? If you can make sure to include the ticker symbol, aggregation period & at least the last couple buy/sell orders in the screenshot that'd be great too. Thanks again!
 
I changed the code here...

I also added some bits that should eliminate all repaints plus should give more "true to life" method for entries and exits...


#################################################################################
# SlimRibbonSuperTrend #
# SlimRibbon study with SuperTrend ATR #
# Author: Eddielee394 #
# Version: 0.2 #
# inspired by: SlimRibbon by Slim Miller and further customized by Markos #
#################################################################################

SetChartType(ChartType.CANDLE_TREND);

input price = close;

input superfast_length = 8;

input fast_length = 13;

input slow_length = 21;

input displace = 0;

input atrMult = 1.2;
#hint atrMult: increases the sensitivity of the ATR line

input nATR = 3;
#hint nATR:

input avgType = AverageType.HULL;
#hint avgType: sets the average type used to calculate the SuperTrendATR

input enableAlerts = no;
#hint enableAlerts: disables all alerts

input hideMovingAverages = yes;
#hint hideMovingAverages: hides all the moving average lines from the slimRibbon

input hideSuperTrendAtr = no;
#hint hideSuperTrendAtr: hides the SuperTrend ATR line

input tradesize = 1;

def ATR = MovingAverage(avgType, TrueRange(high, close, low), nATR);

def UP = HL2 + (atrMult * ATR);

def DN = HL2 + (-atrMult * ATR);

def ST = if close < ST[1] then UP else DN;

plot SuperTrend = ST;
SuperTrend.AssignValueColor(if close < ST then Color.RED else Color.GREEN);
SuperTrend.SetHiding(hideSuperTrendAtr);

def SuperTrendUP = if ST crosses below close[0] then 1 else 0;
def isSuperTrendUP = SuperTrend > close;
def SuperTrendDN = if ST crosses above close[0] then 1 else 0;
def isSuperTrendDN = SuperTrend < close;

#moving averages
def mov_avg8 = ExpAverage(price[-displace], superfast_length);

def mov_avg13 = ExpAverage(price[-displace], fast_length);

def mov_avg21 = ExpAverage(price[-displace], slow_length);

plot Superfast = mov_avg8;
Superfast.SetHiding(hideMovingAverages);

plot Fast = mov_avg13;
Fast.SetHiding(hideMovingAverages);

plot Slow = mov_avg21;
Slow.SetHiding(hideMovingAverages);


def buy = mov_avg8 > mov_avg13 and mov_avg13 > mov_avg21 and low > mov_avg8;

def stopbuy = mov_avg8 <= mov_avg13;

def buynow = !buy[1] and buy;

def buysignal = CompoundValue(1, if buynow and !stopbuy then 1 else if buysignal[1] == 1 and stopbuy then 0 else buysignal[1], 0);

plot Buy_Signal = buysignal[1] == 0 and buysignal == 1;

Buy_Signal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

Buy_Signal.SetDefaultColor(Color.GREEN);

Buy_Signal.HideTitle();

plot Momentum_Down = buysignal[1] == 1 and buysignal == 0;

Momentum_Down.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

Momentum_Down.SetDefaultColor(Color.YELLOW);

Momentum_Down.HideTitle();

def sell = mov_avg8 < mov_avg13 and mov_avg13 < mov_avg21 and high < mov_avg8;

def stopsell = mov_avg8 >= mov_avg13;

def sellnow = !sell[1] and sell;

def sellsignal = CompoundValue(1, if sellnow and !stopsell then 1 else if sellsignal[1] == 1 and stopsell then 0 else sellsignal[1], 0);


plot Sell_Signal = sellsignal[1] == 0 and sellsignal;

Sell_Signal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

Sell_Signal.SetDefaultColor(Color.RED);

Sell_Signal.HideTitle();

plot Momentum_Up = sellsignal[1] == 1 and sellsignal == 0;

Momentum_Up.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

Momentum_Up.SetDefaultColor(Color.YELLOW);

Momentum_Up.HideTitle();

plot Colorbars = if buysignal == 1 then 1 else if sellsignal == 1 then 2 else if buysignal == 0 or sellsignal == 0 then 3 else 0;

Colorbars.Hide();

Colorbars.DefineColor("Buy_Signal_Bars", Color.GREEN);

Colorbars.DefineColor("Sell_Signal_Bars", Color.RED);

Colorbars.DefineColor("Neutral", Color.YELLOW);

AssignPriceColor(if Colorbars == 1 then Colorbars.Color("buy_signal_bars") else if Colorbars == 2 then Colorbars.Color("Sell_Signal_bars") else Colorbars.Color("neutral"));

#Orders
def sellTrigger = if SuperTrendDN or Sell_Signal then 1 else 0;
def buyTrigger = Buy_Signal;

AddOrder(OrderType.BUY_TO_OPEN, condition = buyTrigger, price = open + ticksize(), tradeSize = tradesize, tickcolor = Color.CYAN, arrowcolor = Color.CYAN, name = "Buy");

AddOrder(OrderType.SELL_TO_CLOSE, condition = sellTrigger, price = close, tradeSize = tradesize, tickcolor = Color.PINK, arrowcolor = Color.DARK_RED, name = "Sell");


#Alerts

Alert(condition = enableAlerts and buysignal[1] == 0 and buysignal == 1, text = "Buy Signal", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and buysignal[1] == 1 and buysignal == 0, text = "Momentum_Down", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and sellsignal[1] == 0 and sellsignal == 1, text = "Sell Signal", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and sellsignal[1] == 1 and sellsignal == 0, text = "Momentum_Up", sound = Sound.Bell, "alert type" = Alert.BAR);

#end strategy
 
I've been tooling around with it on the 5m, just downloaded it literally 10 mins ago. I'm really liking it for scalps on the 5 min, seems to not be phased by false moves upward.
 
Where i have the circle is where the order "close" used to show up but now its shows up in the bottom. Not sure if you found the repaint issue and fixed it but it seems to be working fine now.
Cool, thanks for the screenshot & additional info. I believe there may be some confusion here regarding what specifically occurs when a study repaints (in addition to some misleading visual quirks with the strategy buy/sell order arrows & ThinkOrSwim). Repainting is when a signal, indicator, etc for a past candle changes based on the value of a future one. For example, a sell signal on the 3rd candle appears after the 5th candle makes a new low. That would be considered a repaint. In a live environment, we can't go back in time to trade that sell signal since it already happened. The ZigZag indicator is a good example, since preceding lows can't be defined until a new subsequent high is established.

In the case of this specific script I haven't been able to identify any cases where repainting occurs. Additionally, the signal logic is based on various moving average crossovers which by their very nature are lagging indicators - hence the buy/sell condition would need to be satisfied PRIOR to the signal being triggered. What I think you may be seeing is an order signal momentarily displaying before the close of the condition candle and then the condition being invalidated before the candle close - causing the signal to disappear. This is expected behavior & wouldn't be considered a repaint as entry/exit signal is only confirmed upon close of the condition candle. It shouldn't affect back testing results either. The caveat to that is TOS has some quirky behavior with the AddOrder() function where the order arrow will display on the bar after the condition is met, even though the actual price for that order is based on the closed condition bar. There's workarounds for it, but i just haven't tried implementing any yet.

Code:
def SuperTrendUP = if ST crosses below close then 1 else 0;

def SuperTrendDN = if ST crosses above close then 1 else 0;

Code:
AddOrder(OrderType.BUY_TO_OPEN, condition = buyTrigger, price = open + ticksize(), tradeSize = tradesize, tickcolor = Color.CYAN, arrowcolor = Color.CYAN, name = "Buy");

The modifications here use historical prices from bars preceding the signals. The SuperTrend* boolean conditions should only return true if the subsequent bar crosses over. So looking at this it's actually the opposite of true to life since the buy prices are prices that occur before the actual signals trigger.

Also when using the open price for the the buy order, the condition would need to be fulfilled before the trigger - hence the candle would need to already be closed. This instead says enter an order for the open price of a candle that's already closed above that value. I'm not sure why tickSize() is being added the to the open price. That'll further skew any p&L analysis. It's even more prevalent when you do a side by side P&L comparsion (see screenshot - original code on left, modified on right). There's a pretty significant increase in P&L for the right chart due to entries being made based on the open price of what would be in real life unconfirmed buy signals.
2BYPElo.png


What I did notice from your screenshot is that when a buy signal triggers while price is already below the StATR, and a subsequent sell is triggered it fires the sell order 1 candle later than it should be, instead of on the confirmation of the SL sell signal. So i'll have to figure out a better way to integrate the atr crossover & the slim ribbon sell signals. That explains your comment in the screenshot about the sell signal placement. I appreciate you bringing that to my attention :)
 
I've been tooling around with it on the 5m, just downloaded it literally 10 mins ago. I'm really liking it for scalps on the 5 min, seems to not be phased by false moves upward.
Be cautious on smaller time frames (<15min) particularly during choppy/consolidation periods. It fires ALOT of false signals. On my 5min charts I like it more as a reference than a dependency, if that makes any sense.
 
I've been experimenting with a further modified version of the Slim Ribbon indicator that Markos had originally customized. I've converted it to a strategy along with integrating the SuperTrend ATR, slightly modified the sell signal conditions and a couple other minor tweaks. This is a very early beta version that still requires a good amount of testing and modification to the code, so I'm looking for other members they may be interested in trying it out and offering feedback.

All of the testing I've done so far has been long positions only (no short entries). I've been using this intraday primarily on 5min, 15min & 78 min time frames with pretty decent results (see screenshot below). Generally, I'll use the 78min for a short term swing trend confirmation, 15min to confirm intraday trend reversals & 5min for entries/exits. Buy signals are currently based on the parameters from the original indicator, while sell signals are a combination of the SuperTrendATR crossover and/or the sell signal parameter from the original study. I pretty much only pay attention to the strategy order entries/exit signals & not so much the arrows fired by the study (although I've left them active as early "warning" signals of trend changes in addition to testing/debugging purposes).

Most of the backtesting & performance analysis I've done so far has been on the /ES and haven't done any extensive backtesting on equities, although I have been using it on equities during my live trading as a trend confirmation tool and it's proved to be pretty helpful so far. Would be interested to do further equity backtesting with hard performance analysis.

As far as settings, I've set the default values to the settings that I've seen the best performance on based on the backtests so far (ATR mult: 1.2 & natr: 3). But, I'd be interested to see the performance based on other tweaks to the settings.

Note: this is a VERY, VERY early version of the script - so please keep that in mind when testing.

Early Performance Assessment:

Symbol: /ES
TimeFrame: 30 day/15min
PositionSize: 1 contract

eUiQnJV.png


Study link: https://tos.mx/veElNOu

Python:
#################################################################################
# SlimRibbonSuperTrend                                                         
# SlimRibbon study with SuperTrend ATR                                         
# Author: Eddielee394                                                          
# Version: 0.2                                                                 
# inspired by: SlimRibbon by Slim Miller and further customized by Markos      
#################################################################################

SetChartType(ChartType.CANDLE_TREND);

input price = close;

input superfast_length = 8;

input fast_length = 13;

input slow_length = 21;

input displace = 0;

input atrMult = 1.2;
#hint atrMult: increases the sensitivity of the ATR line

input nATR = 3;
#hint nATR:

input avgType = AverageType.HULL;
#hint avgType: sets the average type used to calculate the SuperTrendATR

input enableAlerts = no;
#hint enableAlerts: disables all alerts

input hideMovingAverages = yes;
#hint hideMovingAverages: hides all the moving average lines from the slimRibbon

input hideSuperTrendAtr = no;
#hint hideSuperTrendAtr: hides the SuperTrend ATR line

input tradesize = 1;

def ATR = MovingAverage(avgType, TrueRange(high, close, low), nATR);

def UP = HL2 + (atrMult * ATR);

def DN = HL2 + (-atrMult * ATR);

def ST = if close < ST[1] then UP else DN;

plot SuperTrend = ST;
SuperTrend.AssignValueColor(if close < ST then Color.RED else Color.GREEN);
SuperTrend.SetHiding(hideSuperTrendAtr);

def SuperTrendUP = if ST crosses below close[-1] then 1 else 0;
def isSuperTrendUP = SuperTrend > close;
def SuperTrendDN = if ST crosses above close[-1] then 1 else 0;
def isSuperTrendDN = SuperTrend < close;

#moving averages
def mov_avg8 = ExpAverage(price[-displace], superfast_length);

def mov_avg13 = ExpAverage(price[-displace], fast_length);

def mov_avg21 = ExpAverage(price[-displace], slow_length);

plot Superfast = mov_avg8;
Superfast.SetHiding(hideMovingAverages);

plot Fast = mov_avg13;
Fast.SetHiding(hideMovingAverages);

plot Slow = mov_avg21;
Slow.SetHiding(hideMovingAverages);


def buy = mov_avg8 > mov_avg13 and mov_avg13 > mov_avg21 and low > mov_avg8;

def stopbuy = mov_avg8 <= mov_avg13;

def buynow = !buy[1] and buy;

def buysignal = CompoundValue(1, if buynow and !stopbuy then 1 else if buysignal[1] == 1 and stopbuy then 0 else buysignal[1], 0);

plot Buy_Signal = buysignal[1] == 0 and buysignal == 1;

Buy_Signal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

Buy_Signal.SetDefaultColor(Color.GREEN);

Buy_Signal.HideTitle();

plot Momentum_Down = buysignal[1] == 1 and buysignal == 0;

Momentum_Down.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

Momentum_Down.SetDefaultColor(Color.YELLOW);

Momentum_Down.HideTitle();

def sell = mov_avg8 < mov_avg13 and mov_avg13 < mov_avg21 and high < mov_avg8;

def stopsell = mov_avg8 >= mov_avg13;

def sellnow = !sell[1] and sell;

def sellsignal = CompoundValue(1, if sellnow and !stopsell then 1 else if sellsignal[1] == 1 and stopsell then 0 else sellsignal[1], 0);


plot Sell_Signal = sellsignal[1] == 0 and sellsignal;

Sell_Signal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

Sell_Signal.SetDefaultColor(Color.RED);

Sell_Signal.HideTitle();

plot Momentum_Up = sellsignal[1] == 1 and sellsignal == 0;

Momentum_Up.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);

Momentum_Up.SetDefaultColor(Color.YELLOW);

Momentum_Up.HideTitle();

plot Colorbars = if buysignal == 1 then 1 else if sellsignal == 1 then 2 else if buysignal == 0 or sellsignal == 0 then 3 else 0;

Colorbars.Hide();

Colorbars.DefineColor("Buy_Signal_Bars", Color.GREEN);

Colorbars.DefineColor("Sell_Signal_Bars", Color.RED);

Colorbars.DefineColor("Neutral", Color.YELLOW);

AssignPriceColor(if Colorbars == 1 then Colorbars.Color("buy_signal_bars") else if Colorbars == 2 then Colorbars.Color("Sell_Signal_bars") else  Colorbars.Color("neutral"));

#Orders
def sellTrigger = if SuperTrendDN or Sell_Signal then 1 else 0;
def buyTrigger = Buy_Signal;

AddOrder(OrderType.BUY_TO_OPEN, condition = buyTrigger, price = close, tradeSize = tradesize, tickcolor = Color.CYAN, arrowcolor = Color.CYAN, name = "Buy");

AddOrder(OrderType.SELL_TO_CLOSE, condition = sellTrigger, price = close[-1], tradeSize = tradesize, tickcolor = Color.PINK, arrowcolor = Color.DARK_RED, name = "Sell");


#Alerts

Alert(condition = enableAlerts and buysignal[1] == 0 and buysignal == 1, text = "Buy Signal", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and buysignal[1] == 1 and buysignal == 0, text = "Momentum_Down", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and sellsignal[1] == 0 and sellsignal == 1, text = "Sell Signal", sound = Sound.Bell, "alert type" = Alert.BAR);

Alert(condition = enableAlerts and sellsignal[1] == 1 and sellsignal == 0, text = "Momentum_Up", sound = Sound.Bell, "alert type" = Alert.BAR);

#end strategy
Here's a monkey wrench,.......https://tos.mx/Fu4tUd3
 
Here is a backtest of your original strategy (first post) on an hourly chart, going back to January of 2009 - obviously a "Long Only" strategy will be profitable over the past ten years, but after 2013, it seems like a pretty tradeable P&L curve.

EDIT: P&L isn't as good as I originally thought. 1200+ trades into the backtest (December 2018), the net profit is only $2,686.10. That's pretty poor performance for a Long Only strategy when the overall market goes from 666 to 1830.

kDwIE4p.png


uxFAZLb.png
 
Last edited:

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

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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