Repaints "The System" Moving Average Cross w/ Pullbacks For ThinkOrSwim

Repaints

Chemmy

Active member
I recently talked to a friend who sent me a thread on an SMA cross strategy dubbed "The System", by TraderBJones on twitter. There is a pdf written about it:
https://docs.google.com/presentatio...h2hMEFe7cFIU/edit#slide=id.g118a2787cc5_0_152
though the general strategies follow any typical moving average cross strategies you've seen.

The thread:
https://t.co/GmFVnoqPP9

I wanted to test this quick script, which plots the two SMAs -- according to the documentation, it should either be used on a 30-minute aggregation for intraday trading or daily for swings, so I allowed for MTF aggregation since we both trade on lower time frames. As an idea, I wanted to see if better entries or adding opportunities could be found by combining this with peaks and valleys, particularly those that qualified as market pullbacks (5% or more):

bAeVH19.png


In general, this should be used to follow the rules of "The System" as it's written, but the identification of strong peaks during a bearish trend or strong valleys during a bullish trend within the system should allow for optimal entries in the direction of the System's trend, while the trend is still strong.

This is just a test script, so if anyone sees any promise in this you're welcome to improve it. Thanks to @halcyonguy for their incredible market pullback study: https://usethinkscript.com/threads/identifying-market-pullback-i-e-5.12744/#post-108853

Code:
# The System
# By @TraderBJones on twitter
# Coded by Chemmy for useThinkScript.com


# corrections_peak_to_valley_00 portion credits
#https://usethinkscript.com/threads/identifying-market-pullback-i-e-5.12744/
#Identifying Market Pullback (i.e. 5%+)
# Thread starterscottsamesame  Start dateToday at 9:01 AM

#.........................................
# ref: peak/valley code , robert  post#10
# https://usethinkscript.com/threads/zigzag-high-low-with-supply-demand-zones-for-thinkorswim.172/#post-7048
#.........................................

# Inputs
input fast = 10;
input slow = 50;
input displace = 0;
input showBreakoutSignals = no;
input addlabels = yes;
input agg = aggregationPeriod.THIRTY_MIN;
def price1 = close(period=agg);
def price2 = close(period=agg);

## SMA plots
plot SMAFast = Average(price1[-displace], fast);
plot SMASlow = Average(price2[-displace], slow);

# Signals plots
plot UpSignal = SMAFast crosses above SMASlow;
plot DownSignal = SMAFast crosses below SMASlow;

UpSignal.SetHiding(!showBreakoutSignals);
DownSignal.SetHiding(!showBreakoutSignals);


## Look and feel settings
SMAFast.SetDefaultColor(GetColor(1));
SMASlow.SetDefaultColor(GetColor(3));
UpSignal.SetDefaultColor(Color.UPTICK);
UpSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
DownSignal.SetDefaultColor(Color.DOWNTICK);
DownSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

SMAFast.AssignValueColor(if SMAFast >= SMASlow then color.Light_Green else color.Light_Red);
SMASlow.AssignValueColor(if SMAFast >= SMASlow then color.Dark_Green else color.Red);

SMASlow.SetLineWeight(3);

AddLabel(addlabels, if SMAFast >= SMASlow then "System UP" else "System DOWN", if SMAFast >= SMASlow then color.green else color.red);



### Peak and Valley code
input min_percent_change = 5;
input length = 10;

def na = double.nan;
def bn = BarNumber();
def lastBar = HighestAll(if IsNaN(close) then 0 else bn);
def offset = Min(length - 1, lastBar - bn);

def peak = high > highest(high[1], length - 1) and high == GetValue(highest(high, length), -offset);
def valley = low < Lowest(low[1], length - 1) and low == GetValue(Lowest(low, length), -offset);

# set to 0 if peak and valley happen on same bar
def pv = if bn == 1 then 0
  else if peak and valley then 0
  else if peak then 1
  else if valley then -1
  else pv[1];

def peak2 = if bn == 1 then 0
  else if peak and pv[1] != -1 then 0
  else peak;

def valley2 = if bn == 1 then 0
  else if valley and pv[1] != 1 then 0
  else valley;

input color_peak_valley_bars = yes;
input color_remaining_bars = yes;

AssignPriceColor(
       if (peak and color_peak_valley_bars) then Color.LIME
  else if (valley and color_peak_valley_bars) then Color.magenta
  else if (peak and !color_peak_valley_bars) then Color.current
  else if (valley and !color_peak_valley_bars) then Color.current
  else if color_remaining_bars then Color.DARK_GRAY
  else color.current);

def peak_line = if bn == 1 then 0
  else if peak2 then close
  else if valley2[1] then 0
  else peak_line[1];

def valley_line = if bn == 1 then 0
  else if valley2 then close
  else if peak2[1] then 0
  else valley_line[1];

plot zp = if peak_line > 0 then peak_line else na;
zp.setdefaultcolor(color.red);
zp.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

plot zv = if valley_line > 0 then valley_line else na;
zv.setdefaultcolor(color.green);
zv.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

#----------------------------
input gain_drop_stats = yes;

def gain = if pv[1] == 0 then 0
  else if peak2 then round(close - valley_line, 2)
  else 0;
def gain_per = if pv[1] == 0 then 0 else round( 100 * gain/valley_line, 1);
def is_gain_big = (gain_per >= min_percent_change);

addchartbubble((gain_drop_stats and peak2 and valley_line > 0 and gain_per > 1.30), high,
gain + "\n" +
gain_per + " %"
, ( if is_gain_big then color.green else color.gray), yes);

#----------------------------
def drop = if pv[1] == 0 then 0
  else if valley2 then round(peak_line - close, 2)
  else 0;
def drop_per = if pv[1] == 0 then 0 else round( 100 * drop/peak_line, 1);
def is_drop_big = (drop_per >= min_percent_change);

addchartbubble((gain_drop_stats and valley2 and peak_line > 0 and drop_per > 1.30), low,
drop + "\n" +
drop_per + " %"
, ( if is_drop_big then color.red else color.gray), no);
#

AddLabel(yes, if (SMAFast >= SMASlow and zp < SMASlow) then "Poss. Entry on Pullback" else " ", if (SMAFast >= SMASlow and zp < SMASlow) then color.green else color.red);

AddLabel(yes, if (SMAFast < SMASlow and zv > SMASlow) then "Poss. Entry on Pullback" else " ", if (SMAFast < SMASlow and zv > SMASlow) then color.red else color.green);


#Alerts
Alert(UpSignal, "System Up!",  Alert.Bar, sound.Ding);
Alert(DownSignal, "System Down!", Alert.Bar, sound.Ding);

# End Code
 
Last edited by a moderator:
I recently talked to a friend who sent me a thread on an SMA cross strategy dubbed "The System", by TraderBJones on twitter. There is a pdf written about it, though the general strategies follow any typical moving average cross strategies you've seen.

The thread:
https://t.co/GmFVnoqPP9

I wanted to test this quick script, which plots the two SMAs -- according to the documentation, it should either be used on a 30-minute aggregation for intraday trading or daily for swings, so I allowed for MTF aggregation since we both trade on lower time frames. As an idea, I wanted to see if better entries or adding opportunities could be found by combining this with peaks and valleys, particularly those that qualified as market pullbacks (5% or more):

bAeVH19.png


In general, this should be used to follow the rules of "The System" as it's written, but the identification of strong peaks during a bearish trend or strong valleys during a bullish trend within the system should allow for optimal entries in the direction of the System's trend, while the trend is still strong.

This is just a test script, so if anyone sees any promise in this you're welcome to improve it. Thanks to @halcyonguy for their incredible market pullback study: https://usethinkscript.com/threads/identifying-market-pullback-i-e-5.12744/#post-108853

Code:
# The System
# By @TraderBJones on twitter
# Coded by Chemmy for useThinkScript.com


# corrections_peak_to_valley_00 portion credits
#https://usethinkscript.com/threads/identifying-market-pullback-i-e-5.12744/
#Identifying Market Pullback (i.e. 5%+)
# Thread starterscottsamesame  Start dateToday at 9:01 AM

#.........................................
# ref: peak/valley code , robert  post#10
# https://usethinkscript.com/threads/zigzag-high-low-with-supply-demand-zones-for-thinkorswim.172/#post-7048
#.........................................

# Inputs
input fast = 10;
input slow = 50;
input displace = 0;
input showBreakoutSignals = no;
input addlabels = yes;
input agg = aggregationPeriod.THIRTY_MIN;
def price1 = close(period=agg);
def price2 = close(period=agg);

## SMA plots
plot SMAFast = Average(price1[-displace], fast);
plot SMASlow = Average(price2[-displace], slow);

# Signals plots
plot UpSignal = SMAFast crosses above SMASlow;
plot DownSignal = SMAFast crosses below SMASlow;

UpSignal.SetHiding(!showBreakoutSignals);
DownSignal.SetHiding(!showBreakoutSignals);


## Look and feel settings
SMAFast.SetDefaultColor(GetColor(1));
SMASlow.SetDefaultColor(GetColor(3));
UpSignal.SetDefaultColor(Color.UPTICK);
UpSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
DownSignal.SetDefaultColor(Color.DOWNTICK);
DownSignal.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);

SMAFast.AssignValueColor(if SMAFast >= SMASlow then color.Light_Green else color.Light_Red);
SMASlow.AssignValueColor(if SMAFast >= SMASlow then color.Dark_Green else color.Red);

SMASlow.SetLineWeight(3);

AddLabel(addlabels, if SMAFast >= SMASlow then "System UP" else "System DOWN", if SMAFast >= SMASlow then color.green else color.red);



### Peak and Valley code
input min_percent_change = 5;
input length = 10;

def na = double.nan;
def bn = BarNumber();
def lastBar = HighestAll(if IsNaN(close) then 0 else bn);
def offset = Min(length - 1, lastBar - bn);

def peak = high > highest(high[1], length - 1) and high == GetValue(highest(high, length), -offset);
def valley = low < Lowest(low[1], length - 1) and low == GetValue(Lowest(low, length), -offset);

# set to 0 if peak and valley happen on same bar
def pv = if bn == 1 then 0
  else if peak and valley then 0
  else if peak then 1
  else if valley then -1
  else pv[1];

def peak2 = if bn == 1 then 0
  else if peak and pv[1] != -1 then 0
  else peak;

def valley2 = if bn == 1 then 0
  else if valley and pv[1] != 1 then 0
  else valley;

input color_peak_valley_bars = yes;
input color_remaining_bars = yes;

AssignPriceColor(
       if (peak and color_peak_valley_bars) then Color.LIME
  else if (valley and color_peak_valley_bars) then Color.magenta
  else if (peak and !color_peak_valley_bars) then Color.current
  else if (valley and !color_peak_valley_bars) then Color.current
  else if color_remaining_bars then Color.DARK_GRAY
  else color.current);

def peak_line = if bn == 1 then 0
  else if peak2 then close
  else if valley2[1] then 0
  else peak_line[1];

def valley_line = if bn == 1 then 0
  else if valley2 then close
  else if peak2[1] then 0
  else valley_line[1];

plot zp = if peak_line > 0 then peak_line else na;
zp.setdefaultcolor(color.red);
zp.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

plot zv = if valley_line > 0 then valley_line else na;
zv.setdefaultcolor(color.green);
zv.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

#----------------------------
input gain_drop_stats = yes;

def gain = if pv[1] == 0 then 0
  else if peak2 then round(close - valley_line, 2)
  else 0;
def gain_per = if pv[1] == 0 then 0 else round( 100 * gain/valley_line, 1);
def is_gain_big = (gain_per >= min_percent_change);

addchartbubble((gain_drop_stats and peak2 and valley_line > 0 and gain_per > 1.30), high,
gain + "\n" +
gain_per + " %"
, ( if is_gain_big then color.green else color.gray), yes);

#----------------------------
def drop = if pv[1] == 0 then 0
  else if valley2 then round(peak_line - close, 2)
  else 0;
def drop_per = if pv[1] == 0 then 0 else round( 100 * drop/peak_line, 1);
def is_drop_big = (drop_per >= min_percent_change);

addchartbubble((gain_drop_stats and valley2 and peak_line > 0 and drop_per > 1.30), low,
drop + "\n" +
drop_per + " %"
, ( if is_drop_big then color.red else color.gray), no);
#

AddLabel(yes, if (SMAFast >= SMASlow and zp < SMASlow) then "Poss. Entry on Pullback" else " ", if (SMAFast >= SMASlow and zp < SMASlow) then color.green else color.red);

AddLabel(yes, if (SMAFast < SMASlow and zv > SMASlow) then "Poss. Entry on Pullback" else " ", if (SMAFast < SMASlow and zv > SMASlow) then color.red else color.green);


#Alerts
Alert(UpSignal, "System Up!",  Alert.Bar, sound.Ding);
Alert(DownSignal, "System Down!", Alert.Bar, sound.Ding);

# End Code
@Chemmy thanks for your contribution, are we able to create a scan for the peak and valley bar?
 
@Chemmy thanks for your contribution, are we able to create a scan for the peak and valley bar?
I'm not sure if the peaks and valleys are scannable, and the other study didn't have anyone that was able to accomplish it -- I can make an attempt after market hours to see if it's possible to scan for moves > 5%
 
In the Google Docs presentation, on slide 20, he talks about his particular strategy and introduces a 9/30/50 EMA crossing strategy for entries and exits. That seemed a bit strange after spending so much time describing the 10/50 SMA system, and it's not really clear how the two sets of moving averages play together. However, I decided to throw together the script below to try to implement the particular strategy as described on slide 20.

Notes:
1) The code below is a strategy, not a study. Make sure to create a new strategy item in TOS before pasting in the code.
2) The default values are those described in the Google Docs slides. However, everything, including the price to use for the moving averages (I'm doing some experimenting with this) and moving average types, is an input option.
3) There is an input called "entry Lag". This controls the number of bars in the past to allow a signal to still be valid (MA1 crosses above MA2 within [entryLag] bars). I did this to get around a TOS behavior where some trades should happen on the same bar or immediately adjacent bars but they don't because the system is still on one trade that's being closed and it won't open the new trade. You can play around with the value, but 2 seems to get around the basic issue and more doesn't really change much (change to 1 to see what would happen without the lag parameter).
4) By default, the 10/50 SMA is used to control the direction of the trade (long only when 10 > 50; short only when 10 < 50). There's an input ("use filter") that will turn off this behavior. Using a one-year, daily SPY chart, I get a $15.84 gain without the 10/50 SMA filter vs. a $23.10 loss with it (all other inputs the same). Note that if you do use the filter, you probably want to increase the "entry lag" to allow the filter to flip and still get in a trade.

Code:
#
# The System
# By @TraderBJones on twitter
# Coded by Zetta_wow
#
# Idea from initial post in useThinkScript forum thread:
# https://usethinkscript.com/threads/the-system-indicator-pullbacks-for-thinkorswim.13067/
#
# Linked Google Docs file in that post decribes the strategy.
# This script is based primarily on the 9/30/50 EMA crossing described in that document
# with an option to use the 10/50 SMA as a directional filter.
#

input priceFastMA = close;
input priceExitMA = close;
input priceEntryMA = close;
input fastLength = 9;
input exitLength = 30;
input entryLength = 50;
input averageTypeFastMA = AverageType.EXPONENTIAL;
input averageTypeExitMA = Averagetype.EXPONENTIAL;
input averageTypeEntryMA = AverageType.EXPONENTIAL;
input entryLag = 2;
input priceFastFilterMA = close;
input priceSlowFilterMA = close;
input fastFilterMAlength = 10;
input slowFilterMAlength = 50;
input averageTypeFastFilterMA = AverageType.SIMPLE;
input averageTypeSlowFilterMA = AverageType.SIMPLE;
input useFilter = yes;

plot FastMA = MovingAverage(averageTypeFastMA, priceFastMA, fastLength);
plot SlowMA = MovingAverage(averageTypeExitMA, priceExitMA, exitLength);
plot EntryMA = MovingAverage(averageTypeEntryMA, priceEntryMA, entryLength);
FastMA.SetDefaultColor(GetColor(1));
FastMA.SetLineWeight(3);
SlowMA.SetDefaultColor(GetColor(2));
SlowMA.setLineWeight(3);
EntryMA.SetDefaultColor(GetColor(3));
EntryMA.setlineWeight(3);

plot fastFilterMA = MovingAverage(averageTypeFastFilterMA, priceFastFilterMA, fastFilterMAlength);
plot slowFilterMA = MovingAverage(averageTypeSlowFilterMA, priceSlowFilterMA, slowFilterMAlength);
fastFilterMA.SetDefaultColor(Color.PLUM);
slowFilterMA.SetDefaultColor(Color.VIOLET);
AddCloud(fastFilterMA, slowFilterMA, color1 = Color.LIGHT_GREEN, color2 = Color.LIGHT_RED);

def isEMAbuyLong = FastMA crosses above EntryMA within entryLag bars;
def isEMALongExit = FastMA crosses below SlowMA;
def isEMAsellShort = FastMA crosses below EntryMA within entryLag bars;
def isEMAShortExit = FastMA crosses above SlowMA;
def isFilterLong = if useFilter then fastFilterMA >= slowFilterMA else yes;
def isFilterShort = if useFilter then fastFilterMA < slowFilterMA else yes;

AddOrder(OrderType.BUY_TO_OPEN, isEMAbuyLong and isFilterLong, tradeSize = 1, tickColor = GetColor(1), arrowColor = GetColor(1), name = "MovAvgTwoLinesStratLE");
AddOrder(OrderType.SELL_TO_CLOSE, isEMALongExit, tradeSize = 1, tickColor = GetColor(2), arrowColor = GetColor(2), name = "MovAvgTwoLinesStratSE");
AddOrder(OrderType.SELL_TO_OPEN, isEMAsellShort and isFilterShort, tradeSize = 1, tickColor = GetColor(1), arrowColor = GetColor(1), name = "MovAvgTwoLinesStratLE");
AddOrder(OrderType.BUY_TO_CLOSE, isEMAShortExit, tradeSize = 1, tickColor = GetColor(2), arrowColor = GetColor(2), name = "MovAvgTwoLinesStratSE");
 
it's repaint? thanks
No, it won't repaint -- however you should be aware of how MTF studies work --
if you trade on a 4-hour time frame but aggregate these MAs on a daily timeframe, then you'll want to wait until the full day has passed for full confirmation. Once that happens, though, the confirmation will be final.
 
i understand but i have a 5 minutes charts and 5 minutes on the indicator, an yes the candles keep repainting , the indicator will not repaint but the candles yes.

i was just a comment, i appreciate @Chemmy for share it with us. is look very nice
 
Last edited by a moderator:
i understand but i have a 5 minutes charts and 5 minutes on the indicator, an yes the candles keep repainting , the indicator will not repaint but the candles yes.

i was just a comment, i appreciate @Chemmy for share it with us. is look very nice
Ah, if you're referring to the peaks and valleys portion of the code then yes I believe the colors indicating those will repaint until a peak or valley is confirmed -- I don't think there's any way to fix that, so entries based off them should be treated as you would treat trading off of a pivot.

If you don't like the candle coloring changing though you're welcome to turn the options off in the study settings.
 
I'm not sure if the peaks and valleys are scannable, and the other study didn't have anyone that was able to accomplish it -- I can make an attempt after market hours to see if it's possible to scan for moves > 5%
Any luck on a scan?
 
@Chemmy

I know I already commented, but I just wanted to add that the peaks and valleys on the lower timeframes (1/5/15) with a 30 minute agg is the JUICE for me, crazy that something so simple has transformed my trading.

SPY/TSLA/NVDA/AAPL, incredible results on all of them.

Had to get used to the peaks and valleys skipping a tad when it's a fast moving day, but that's easy to adjust for. Thanks again for this, nothing comes close.
 
Great work anyway to make these EMAs?
I would like the 10 and 50 to be EMAs

UPDATE:
Hey never mind I figured it out, just have the to change to Average to exp Average. Thanks again!
 
Last edited by a moderator:
@Chemmy

I know I already commented, but I just wanted to add that the peaks and valleys on the lower timeframes (1/5/15) with a 30 minute agg is the JUICE for me, crazy that something so simple has transformed my trading.

SPY/TSLA/NVDA/AAPL, incredible results on all of them.

Had to get used to the peaks and valleys skipping a tad when it's a fast moving day, but that's easy to adjust for. Thanks again for this, nothing comes close.
Are you still using this as your strategy? Have you made any adjustments?
 
@Chemmy I'm sorry I just now perused this thread and thank you for your thoughtful and creative amalgamation of two strategies. To clarify, is the idea to go long when a pink/magenta candle appears, and perhaps continue to add more as additional pink/magenta candles appear? Likewise to sell and/or go short when the lime/yellow candles appear? If not, can you please explain how to use this strategy? I notice when examining the magenta and yellow candles on the daily chart of the S&P 500 that there are many instances of strikingly good signals using the simple approach I just described, although when I apply a floating p/l graph over the past year, the results show a cumulative loss. Interestingly, the floating p/l shows a gain over the past 5 years. In any case, examining the chart by hand over the past year shows some great calls. I suspect I'm still missing something rudimentary and vital, and I'm sorry for that. Can you say how to use the system properly? Thank you for any thoughts and for sharing also something very creative as you have.
 

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
338 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