Automated MACD Backtest Strategy for ThinkorSwim

WayneG

New member
VIP
Below is a Mobius Strategy for MACD. Please note the date: January 7, 2012, so it is a little on the old side. It does run on the current version of ThinkorSwim and appears to auto-trading in the onDemand mode, however it does trade when using Paper Trading and that is the question, does Paper Trading support auto trade?

I found this in an old blog of Mobius. It is at: http://rr-corner.squarespace.com/mobius-cave-non-member/

There are many old scripts written by Mobius. Please post update and modification to this script so everyone may benefit from your effort.

Code:
# MACD Strategy
# Mobius
# [email protected]
# V.01.07.2012

#hint: The MACD Strategy uses a MACD to generate Buy and Sell signals.
#          \n In the dafault mode it is always in the #market either Long or Short.
#          \n A Fractal Choppiness Indicator is used to #disable the Buy signal when
#              the equity is in a Choppy Zone.
#          \n Hints are at each variable click on the ? #icon.
#wizard input: n_f
#wizard text: n_f:
#hint n_f: Periods for the Fast EMA.
#wizard input: n_s
#wizard text: n_s:
#hint n_s: Periods for the Slow EMA.
#wizard input: n_n
#wizard text: n_n:
#hint n_n: Period for the Slow EMA Smoothing Function.
#wizard input: SellEndOfDay
#wizard text: SellEndOfDay:
#hint SellEndOfDay: Yes = Postion closed at the end of the day.
#           \n The signal is sent on the opening of the #next bar so make
#              sure to leave enough time for the close to #be carried out.
#wizard input: CloseTime
#wizard text: CloseTime:
#hint CloseTime: Time is Eastern Standard Time.
#wizard input: MinBeforeClose
#wizard text: MinBeforeClose:
#hint MinBeforeClose: Minutes before 1600 when the signal #is assigned.
#         \n The close will actually happen  at the open #of the following bar.
#wizard input: nC
#wizard text: nC:
#hint nC: Periods for the calculation of the Fractal Choppiness Indicator.
#wizard input: nCA
#wizard text: nCA:
#hint nCA: Periods to calculate the Average value for the Fractal Choppiness Indicator.
#wizard input: Choppy
#wizard text: Choppy:
#hint Choppy: Value indicating the beginning of the Choppy #Zone.
#               \n (Usually a value between 50 and 61.8)
#               \n Buy Signals will not be generated in #the Choppy Zone.
#               \n To disable this feature set the Value #at 100.
#wizard input: CIx
#wizard text: CIx:
#hint CIx: CIB uses the Choppiness Indicators (B)ase line #as the signal line.
#                \n CIA uses the (A)verage of the #Choppiness Indicator.

input n_f = 13;
input n_s = 21;
input n_n =  8;
input SellEndOfDay = yes;
input CloseTime = 1600;
input MinBeforeClose = 10;
input nC       = 34;
input nCA      =  8;
input Choppy   = 61.8;
input CIx = {default CIB, CIA};

def o = open;
def h = high;
def l = low;
def c = close;
def Seconds = MinBeforeClose * 60;
def secondsRemained = SecondsTillTime(CloseTime);
def F = (c * .15) +  (.85  * ExpAverage(c, n_f)[1]);
def SS = (c * .075) + (.925 * ExpAverage(c, n_s)[1]);
def MACD   = F - SS;
def MACDSL = ExpAverage(MACD, n_n);
def zero   = 0;

# Fractal Choppiness Indicator

def CIA = 100 * Log( Sum( TrueRange(h, c, l), nC))
               / ( Highest(c[1], nC) - Lowest(c[1], nC))
               / Log(nC);

def CIB = ((Log(Sum(TrueRange(h, c, l), nC) /
              (Highest(if h >= c[1]
                       then h
                       else c[1], nC) - Lowest( if l <= c[1]
                                                then l
                                                else c[1], nC))) / Log(10)) / (Log(nC) / Log(10))) * 100;
def CI = if CIx == CIx.CIB
            then CIB
            else CIA;
def CIavg = Average(CI, nCA);
def ex    = if CIavg > Choppy
               then 1
               else 0;

# Chart Management
AssignPriceColor(if ex == 1
                    then Color.YELLOW
                    else if MACD > 0 and
                            MACD > MACD[1] and
                            MACD[1] > MACD[2]
                         then Color.GREEN
                         else if MACD < 0 and
                                 MACD > MACDSL
                         then Color.GRAY
                         else if MACD crosses above 0
                         then Color.WHITE
                         else if MACD crosses below 0
                         then Color.BLUE
                         else Color.RED);

# Order Management

def buy = ex != 1 and
               ( MACD > MACDSL and
                 MACD > 0 or
                 MACD crosses Lowest(MACD, n_s));
def sell = if SellEndOfDay == yes
              then
                ( secondsRemained >= 0 and
                  secondsRemained <= Seconds
                ) or
                 ( MACD < MACDSL and
                   MACDSL < MACDSL[1] and
                   MACDSL[1] > MACDSL[2]
                 ) or
                   MACD crosses below 0
                   or
                   MACD crosses Highest(MACD, n_s)
             else
                 ( MACD < MACDSL and
                   MACDSL < MACDSL[1] and
                   MACDSL[1] > MACDSL[2]) or
                   MACD crosses below 0 or
                   MACD crosses Highest(MACD, n_s)
              ;

AddOrder(OrderType.BUY_AUTO, condition = buy,
                             price = open,
                             tickcolor = Color. GREEN,
                             arrowcolor = Color.GREEN,
                             name = "BUY");

AddOrder(OrderType.SELL_AUTO, condition = sell,
                              price = open,
                              tickcolor = Color.RED,
                              arrowcolor = Color.RED,
                              name = "SELL");

# End Code

I forgot to include his notes on this script.

Here's a very simple STRATEGY to get some of you fine coders to start thinking of taking things to the next level.

Put this in the STRATEGY NOT study part of TOS. Note the different profits as you scroll through the aggregations. Keep in mind as aggregations change so does the length of the reported times. A separate spread sheet of profit and loss is available by right clicking on any of the Buy
or Sell points and using the Show Report function.

The Strategy, as written, is always in the market either long or short. It could easily be changed to just be a long or just a short strategy. There are many enhancements that could be made. A choppiness indicator to keep it out of trades at appropriate times. A time filter to shut it off during parts of the day. Additional non-colinear indicators such as a stochastic to identify momentum or RSI. Linear Regression could be used to allow trades only in a certain type of trending market.

The point is there is a lot more than just drawing lines, dots and colors on charts available to us.
 
Last edited:
The script provided above does not plot buys and sells at appropriate price level (meaning it will plot a buy or sell entry at a price that is not possible on the candle it claims to enter on). This will cause false results in the strategy report so it is indeterminable if the results are better or worse than it should actually be. Would have to forward test it.
 
Granted the buy/sell routine is not correct, but I was more concerned about the quality of the MACD sections of the program. While compiling correctly, it just goes to show us how loose the compiler is.

Thanks, wayneG
 
I stumbled on this and gave it a try. Also dug a little deeper into the comment by "tradebyday". It appears that a simple code change to the price from open to close makes the buy and sell entries possible, but the results considerably less attractive. See below:

Code:
AddOrder(OrderType.BUY_AUTO, condition = buy,
                             price = CLOSE,
                             tickcolor = Color. GREEN,
                             arrowcolor = Color.GREEN,
                             name = "BUY");
AddOrder(OrderType.SELL_AUTO, condition = sell,
                              price = CLOSE,
                              tickcolor = Color.RED,
                              arrowcolor = Color.RED,
                              name = "SELL");

The code includes the following comment:

# \n In the default mode it is always in the #market either Long or Short.

I am trying to find where the mode can be set for only long or only short. Does it exist in the code and I am just not seeing it? If so, please tell me where to look. Thanks.
 
@tradebyday Thank you. I did try that but it wasn't clear if that was the only code change required. By doing that, there are times when the code causes a buy to open into a long position when it is clear from the price action and indicator that it should be creating a sell to go short. In those situations, it seems to let the price drop considerably before creating a sell to close (which looks like a good place for a buy to close if it were a short strategy). I'm going to take a stab at adding a stop loss sell order to the code. Not sure exactly how yet, but worth a try.
 
I was originally blown away by the insane P/L, however, the buy and sell orders starts with the open of the candle. This needs to be replaced with the close of the candle for confirmation. When changing it to close, the P/L is mostly neg (I just spot checked a few timeframes).

If you find more of these scripts please post!

Thanks!

:)
 
@adii800 I didn't check the code but if that is the case, you are correct. Buy and sell orders should be set to "close" to ensure some level of accuracy.
 
The strategy is absolutely cracked when set to open, literally raking in thousands on a daily basis and million + on a monthly with one contract on /ES, thought it was the holy grail, sad that it was not real lol
 
All TOS script does not plot buys and sells at appropriate real price level. This cause false results in the strategy report so it is indeterminable if the results are better or worse than it should actually be. Is there a way to replace the standard input (open or close) with the price level where strategy condition triggers?
 
All TOS script does not plot buys and sells at appropriate real price level. This cause false results in the strategy report so it is indeterminable if the results are better or worse than it should actually be. Is there a way to replace the standard input (open or close) with the price level where strategy condition triggers?
While one can never mirror live conditions using the strategy (to my knowledge) due to bid-ask spreads, volatility, slippage, etc. you can make the price = close in the order part of your strategy as BenTen said...

If you really wnat to test the robustness of your strategy you could even set the order price equal to something along the lines of this: (open[-1]+close[-1])/2

This could be done to account for the bid-ask spreads. tbh, I feel like this is total overkill though and instead, you could manually just subtract one ticks worth of slippage times the number of trades from your profit, i.e. setting the order price to open[-1] +/- 1 accordingly... that should be adequate. :)
 
you could manually just subtract one ticks worth of slippage times the number of trades from your profit, i.e. setting the order price to open[-1] +/- 1 accordingly... that should be adequate. :)
Agree, open[-1] is unreal, so I set close[-1] +/- 2 ticks trying to get close to a real performance, but there's a huge difference on backtesting results if you set close[-1], close[-1] +/-1 or close[-1] +/- 2 ticks, and nobody talks about that.
 
Agree, open[-1] is unreal, so I set close[-1] +/- 2 ticks trying to get close to a real performance, but there's a huge difference on backtesting results if you set close[-1], close[-1] +/-1 or close[-1] +/- 2 ticks, and nobody talks about that.
yes, I agree. Many also consider %profitable as the best metric for evaluating a strategy but in my experience, the win/loss ratio is the best. Because even if there is slippage, volatility, etc. Your strat should still be profitable!
 
3 main factors when evaluating the viability of the strategy. #1 being drawdown. No matter what kind of strategy you run, if your account can't handle the drawdown, you'll never survive. #2 and #3 go hand in hand when determining the viability of the strategy: win/loss ratio and your avg win/loss values. The reason these go hand in hand is because you can have a 30% win percentage if your winners are 5 times bigger than your losers, or an 80% win percentage may be useless if your avg winner is 1/10th your average losers. My criteria for an effective strategy (automated) is anything 50+% winning, with no less than a 1.5:1 average winner to loser. This ensures the strategy in use (which if automating signals most likely has a high frequency of signals) that you're dealing with something vastly in your favor. Variables that could greatly affect these data sets are time of day the strategy is enforced, and whether your in high or low volatility market conditions
 
Hi! I am completely new to this forum and thinkscript. I have no idea how to code at all. I am trying to create a strategy where the buy signal is created when price is above the EMA 200, MACD crosses, and the MACD cross happens below the 0 line.

For shorting signal: Price is below 200 EMA, MACD cross, and the MACD cross happens above the 0 line.

I tried using the MACD strat default on tos as a template but I could not get anywhere with that and have no idea what to do. Can someone please help me with this? I'd greatly appreciate it :)
 
@Urashima If you are looking to learn how to Thinkscript you could start in the Learning Center... It sounds like you'd rather learn than to just have someone else do the work and hand you the code... If so, I commend you for that...

One way to learn would be to use the TOS Scanner OR the Condition Wizard in the Studies/Strategies code panel... Another way would be to peruse the standard Studies and Strategies included in TOS, as well as those posted here in the forums... It all starts with baby steps... Some folks don't have the patience, or think they don't, but it feels rewarding to see your won code display the results you want... I've been coding in a multitude of languages over the past 36 years and still love it... Yikes, I'm old...!!!
 

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

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
335 Online
Create Post

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