SPX Trading Strategy for ThinkorSwim

Status
Not open for further replies.
No, dude, thank you. This developing study is quite amazing. I don't have too much coding knowledge, but I'm happy to contribute by testing/experimenting.

1. Another request, if you think they're useful: exitat ergodicosc alone and profitdeltaorergodicosc. @Hypoluxa mentioned in the op that you could potentially ride it out till ergodic turns on you. My observations are that it appears better for longer runs than macd alone.

2. Not sure what's happened with your latest update and if it's accurate, but the winrate for macd alone has dropped a ton. I'm showing 38% winrate on my settings where it was previously 89%. Are you sure it's accurate?

3. When I try to set cross distance to 0 (experimenting), I'm not sure it's showing accurate winrate because it shows the same winrate if I change it to -.5, -1, etc. Is this working properly or is there something wrong?

4. What does bb cross in bars do exactly? I don't understand from the code. I knw you mentioned that it will allow less or more trades depending on its value change, but can you please explain what it changes exactly? Is it something I can see on the macd indicator?
I’ll look into adding more strategies into it as options. Since the initial goal was to just count the wins, code is not well structured to add other strategies easily.

There has been bug fixes from comments. Try the latest version posted a few mins ago.

Dont set the cross distance to zero. It should be at least 0.01. Warning is fired at zero. I’ll look into making it more flexible.

BB cross bars determines a valid crossing of BB to happen in that many bars. This filters out a very slow moving market and chopping in one direction. Since this was mostly a momentum based options scalping strategy, it needed to be quantified.
 
Update...If you are using this with futures other than /ES, we need to add margin requirements for each future. Profit value is calculated with tick value. It will auto adjust on each futures type, but the ROI percentage depends on the margin requirement. If you are trading options, PnL and ROI is probably not relevant to you.

Python:
# SPX Strategy
# Strategy designed by Hypoluxa
# barbaros - v1  - 2021/02/25
# barbaros - v2  - 2021/02/25 - added warning arrows, alerts, statistics and non SPX trading option
# barbaros - v3  - 2021/02/26 - added SMA plots, chart type, and price plot
# barbaros - v4  - 2021/03/02 - added trade time limit and do not cross before start time
# barbaros - v5  - 2021/03/02 - added direction label
# barbaros - v6  - 2021/03/03 - added alerts, exit at profit delta, arrows for exiting position, and changed defaults to show all
# barbaros - v7  - 2021/03/03 - removed inputs for disabling arrows - this can be done in ToS already,
#                              added profit target line, ExitAt selection and ATR target
# barbaros - v8  - 2021/03/05 - added profit target label, changed the exit strategy to high/low instead of close
# barbaros - v9  - 2021/03/06 - added entry price label
# barbaros - v10 - 2021/03/11 - trying to fix before 9:40am EST crossing filter
# barbaros - v11 - 2021/03/11 - removed chart type overwriting
# barbaros - v12 - 2021/03/11 - fixed issue with disabling DoNotCrossBeforeStart
# barbaros - v13 - 2021/03/12 - fixed issue with macdonly win counting
# barbaros - v14 - 2021/03/13 - added PnL and ROI - note: only /ES margin is available

# Setup
# 10 Min chart
# Heikin Ashi candles
# SMA 3/9
# MACD Bollinger Bands (the one Ben has posted on here a while back) 8,16,36 and uncheck "show plot" on the BB upper, BB lower and BB mid line. You will only be using the zero line, MACD dots and MACD Line for entry purposes. The inputs of "b length" and "bb num dev" are irrelevant here since you will remove the the plots that I mentioned.
# ErgodicOsc 2,10,36 (changed the default negative to red)

# Option call logic:
# 1. The SMA's have to cross first.
# 2. For a call opportunity, you will then wait to see if the MACD dots cross above the MACD zero line. Its critical here to wait until one dot has cleared the zero line...you MUST see a gap....never enter with the dot on the line. Dots must be consistent as well...if its going up...then they must all be white...if a red dot populates between the time a white dot hits the zero line and the time one crosses clear....don't enter. I have a screenshot below showing this example - 13:00 a red dot appears.
# 3. The ErgodicOsc HAS to be green when the MACD dot crosses above the zero line. You can hold the trade most of the time until this turns from green to red....but I always set a sell limit just in case it whips back in the opposite direction.

# Option put logic:
# Obviously its the complete opposite of what I've described above for a call. BUT - the SMA's still have to cross first.

# Note:
# Historical price action testing shows that if the MACDBB crosses zerobase before 9:40 EST, do not take the trade. Also, there might be too much choppiness after 15:00 EST.

declare upper;

input AllowNonSPX = no;
input ShowLabels = yes;
input ShowStatistics = yes;
input ExitAt = {default "profitDeltaOrMACD", "MACDOnly", "ATRorMACD"};
input ProfitDelta = 1.0;
input ATRLength = 7.0;
input ATRMult = 0.5;
input LimitTime = yes;
input StartTime = 940;
input StopTime = 1500;
input DoNotCrossBeforeStart = yes;

input price = close;
input SMAFastLength = 3;
input SMASlowLength = 9;
input BBlength = 30;
input BBNum_Dev = 0.8;
input BBCrossInBars = 3;
input BBCrossDistance = 1.0;
input MACDfastLength = 8;
input MACDslowLength = 16;
input MACDLength = 36;
input ERGODICLongLength = 2;
input ERGODICShortLength = 10;
input ERGODICSignalLength = 36;
input ERGODICAverageType = {"SIMPLE", default "EXPONENTIAL", "WEIGHTED", "WILDERS", "HULL"};

# Check for 10min chart
Assert(AllowNonSPX or GetAggregationPeriod() == AggregationPeriod.TEN_MIN, "Incorrect Chart Time, use 10m");
Assert(AllowNonSPX or GetSymbol() == "SPX", "Incorrect Chart Time, use 10m");

# MACD
def MACD_Data = MACD(fastLength = MACDfastLength, slowLength = MACDslowLength, MACDLength = MACDLength);
def MACD_Direction = if MACD_Data > MACD_Data[1] then 1 else -1;
def MACD_CrossBar = if MACD_Data crosses above 0 within 1 bar or MACD_Data crosses below 0 within 1 bar then BarNumber() else MACD_CrossBar[1];
def MACD_CrossBarAgo = BarNumber() - MACD_CrossBar;

# Ergodic
def Ergodic_Data = ErgodicOsc("long length" = ERGODICLongLength, "short length" = ERGODICShortLength, "signal length" = ERGODICSignalLength, "average type" = ERGODICAverageType).ErgodicOsc;

# SMAs
def SMA_Fast = SimpleMovingAvg(price, SMAFastLength);
def SMA_Slow = SimpleMovingAvg(price, SMASlowLength);

# ATR for progit target
def atrDelta = ATR(ATRLength) * ATRMult;

# Time Limit
def isTradeTime = if LimitTime then SecondsFromTime(StartTime) >= 0 and SecondsTillTime(StopTime) >= 0 else yes;
def isNotCrossBeforeStart = if !DoNotCrossBeforeStart then yes
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) == 0 and MACD_CrossBarAgo == 1 then no
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) != 0 and MACD_CrossBar[1] != MACD_CrossBar then yes
                            else isNotCrossBeforeStart[1];

# Signals
def buySignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_Data >= BBCrossDistance and MACD_Data crosses above 0 within BBCrossInBars bars;
def buyWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_CrossBar[1] != MACD_CrossBar;

def sellSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_Data <= -BBCrossDistance and MACD_Data crosses below 0 within BBCrossInBars bars;
def sellWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_CrossBar[1] != MACD_CrossBar;

# Plots
plot buy = buySignal and !buySignal[1];
buy.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buy.setDefaultColor(Color.GREEN);
buy.setLineWeight(3);

plot buyWarn = buyWarnSignal and !buyWarnSignal[1];
buyWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buyWarn.setDefaultColor(Color.CYAN);
buyWarn.setLineWeight(1);

plot sell = sellSignal and !sellSignal[1];
sell.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sell.setDefaultColor(Color.RED);
sell.setLineWeight(3);

plot sellWarn = sellWarnSignal and !sellWarnSignal[1];
sellWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sellWarn.setDefaultColor(Color.MAGENTA);
sellWarn.setLineWeight(1);

plot lastPrice = price;
lastPrice.setPaintingStrategy(PaintingStrategy.POINTS);
lastPrice.setDefaultColor(Color.GREEN);

plot fast = SMA_Fast;
fast.setPaintingStrategy(PaintingStrategy.LINE);
fast.setDefaultColor(Color.CYAN);
fast.setLineWeight(1);

plot slow = SMA_Slow;
slow.setPaintingStrategy(PaintingStrategy.LINE);
slow.setDefaultColor(Color.MAGENTA);
slow.setLineWeight(1);

# PnL
def entryPrice = if (buySignal and !buySignal[1]) or (sellSignal and !sellSignal[1]) then open[-1] else entryPrice[1];
def profitDeltaTarget = if ExitAt == ExitAt.profitDeltaOrMACD then ProfitDelta else if ExitAt == ExitAt.ATRorMACD then atrDelta else 0;
def profitTarget = if buySignal and !buySignal[1] then entryPrice + profitDeltaTarget
                   else if sellSignal and !sellSignal[1] then entryPrice - profitDeltaTarget
                   else profitTarget[1];
def orderDir = if BarNumber() == 1 then 0
               else if orderDir[1] == 0 and buySignal and !buySignal[1] then 1
               else if orderDir[1] == 1 and (MACD_Direction != 1 or (ExitAt != ExitAt.MACDOnly and high >= profitTarget)) then 0
               else if orderDir[1] == 0 and sellSignal and !sellSignal[1] then -1
               else if orderDir[1] == -1 and (MACD_Direction != -1 or (ExitAt != ExitAt.MACDOnly and low <= profitTarget)) then 0
               else orderDir[1];

def isOrder = if IsNaN(orderDir) then no else orderDir crosses 0;
def orderCount = CompoundValue(1, if IsNaN(isOrder) then 0 else if isOrder then orderCount[1] + 1 else orderCount[1], 0);

def orderWinners = if BarNumber() == 1 then 0
                    else if orderDir[1] == 1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) or (close > entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else if orderDir[1] == -1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) or (close < entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else orderWinners[1];
def winRate = orderWinners / orderCount;

def PnL = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
                 PnL[1] + ((close - entryPrice) * TickValue())
           else if orderDir[1] == -1 and orderDir == 0 then
               PnL[1] + ((entryPrice - close) * TickValue())
           else PnL[1];

def costPrice = if GetSymbol() == "/ES:XCME" then 13000
                else entryPrice;
def ROI = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
                 ROI[1] + (((close - entryPrice) * TickValue())/costPrice)
           else if orderDir[1] == -1 and orderDir == 0 then
               ROI[1] + (((entryPrice - close) * TickValue())/costPrice)
           else ROI[1];

# Plot Exit Positions
plot buyExit = orderDir[1] == 1 and orderDir != 1;
buyExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
buyExit.setDefaultColor(Color.GREEN);
buyExit.setLineWeight(3);

plot sellExit = orderDir[1] == -1 and orderDir != -1;
sellExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
sellExit.setDefaultColor(Color.RED);
sellExit.setLineWeight(3);

plot profitTargetLevel = if orderDir != 0 or orderDir[1] != 0 then profitTarget else Double.NaN;
profitTargetLevel.setPaintingStrategy(PaintingStrategy.LINE);
profitTargetLevel.setDefaultColor(Color.GREEN);
profitTargetLevel.setLineWeight(3);

# Labels
AddLabel(ShowLabels, "SPX Strategy", Color.WHITE);
AddLabel(ShowLabels, if buy then "Buy"
                     else if sell then "Sell"
                     else if buyWarn or sellWarn then "Warn"
                     else if orderDir == 1 then "Long"
                     else if orderDir == -1 then "Short"
                     else "Neutral",
                     if buy then Color.GREEN
                     else if sell then Color.RED
                     else if buyWarn then Color.YELLOW
                     else if sellWarn then Color.LIGHT_RED
                     else if orderDir == 1 then Color.YELLOW
                     else if orderDir == -1 then Color.LIGHT_RED
                     else Color.GRAY
);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(entryPrice), "Entry " + AsDollars(entryPrice), Color.GRAY);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(profitTarget), "Target " + AsDollars(profitTarget), Color.GRAY);
AddLabel(ShowLabels and ShowStatistics, "" + orderCount + " Trades | " + AsPercent(winRate), if winRate > 0.5 then Color.GREEN else Color.RED);
AddLabel(ShowLabels and ShowStatistics, "" + AsDollars(PnL) + " | " + AsPercent(ROI), if ROI > 0 then Color.GREEN else Color.RED);

# Alerts
Alert(buy, "Buy", Alert.BAR, Sound.Ring);
Alert(sell, "Sell", Alert.BAR, Sound.Ring);
Alert(buyWarn, "Buy Warning", Alert.BAR, Sound.Ding);
Alert(sellWarn, "Sell Warning", Alert.BAR, Sound.Ding);
Alert(buyExit, "Buy Exit", Alert.BAR, Sound.Ring);
Alert(sellExit, "Sell Exit", Alert.BAR, Sound.Ring);

Thanks again for your work on this.

Ok, I just ran this, default settings on /es, 940-1500, exitat profitdeltaormacd, profitdelta 3 looking back 180 days. Stats provide 155 trades, 69.68% winrate, but only $715.63 profit (over that 6 month period).

Same settings with Macd alone, getting 155 trades, 36.77%, only $1,862.50 profit (over that 6 month period).

Is this accurate or is there a bug in the winrate and p/l calculations?
 
@barbaros Thank you for the great work! I have a quick question. In your code you have input BBNum_Dev = 0.8; whereas @Hypoluxa has bb num dev = 0.5. Is your code still correct or should this be changed? Cheers!
I’ve only seen that the 3rd and 4th numbers are the only ones that changes anything. Try it and see.
 
@Hypoluxa Thank you for this amazing work.. There is no HOLY GRAIL, but your strategy provides opportunities with higher probabilities.. It has helped me overcome FOMO a lot.. Thank you..
 
Thanks again for your work on this.

Ok, I just ran this, default settings on /es, 940-1500, exitat profitdeltaormacd, profitdelta 3 looking back 180 days. Stats provide 155 trades, 69.68% winrate, but only $715.63 profit (over that 6 month period).

Same settings with Macd alone, getting 155 trades, 36.77%, only $1,862.50 profit (over that 6 month period).

Is this accurate or is there a bug in the winrate and p/l calculations?
I believe the statistics are correct. I find that MACD should be used as stoploss and not profit target.
 
Good deal!!! Patience isn’t something I have, so I try to build that with indicators that are tried and true. Lol
You are right.. seeing other people making big gains, for me FOMO always takes over, ive deleted all social media and turned off news on TOS. This platform is the only one I’m active on... Everyone is unique in their style and has a lot knowledge.. I’m just keeping an eye on studies provided by you. I’m tweaking it a little for Tesla and PLTR.. it may take some time but I’m getting there.. thank you
 
You are right.. seeing other people making big gains, for me FOMO always takes over, ive deleted all social media and turned off news on TOS. This platform is the only one I’m active on... Everyone is unique in their style and has a lot knowledge.. I’m just keeping an eye on studies provided by you. I’m tweaking it a little for Tesla and PLTR.. it may take some time but I’m getting there..
Sounds like a good plan. Just trade the chart and indicators in front of you and it’ll workout more than not.
 
I believe the statistics are correct. I find that MACD should be used as stoploss and not profit target.
Understood, but with profitdeltaormacd exitat, profit delta 3, even with a 69% winrate it only made $715 over 6 months. Those numbers don't look right to me. Of course, we don't want to trade 6 months for $715 (commissions would make this a loss). And with such a good winrate, I would assume much more profit. That's why I'm confused.
 
Understood, but with profitdeltaormacd exitat, profit delta 3, even with a 69% winrate it only made $715 over 6 months. Those numbers don't look right to me. Of course, we don't want to trade 6 months for $715 (commissions would make this a loss). And with such a good winrate, I would assume much more profit. That's why I'm confused.
It is completely possible to have a higher win rate but less profit. I used 3pt target for profitdeltaormacg option and it is less of a profit than 1pt target. This is because when you set 3pt, it has such a large loss that small increments don't catch up.

You will need to tune your strategy to your risk as @Hypoluxa said many times. There isn't a specific stoploss for this strategy. I personally use resistance and support levels to determine entries and exists with assistance of this indicator.

This version might help you visualize better. I also made a few more tweaks. You can enable "ShowPnLBubbles" to see how the PnL changes over the chart time.

Let me know what you find.

Python:
# SPX Strategy
# Strategy designed by Hypoluxa
# barbaros - v1  - 2021/02/25
# barbaros - v2  - 2021/02/25 - added warning arrows, alerts, statistics and non SPX trading option
# barbaros - v3  - 2021/02/26 - added SMA plots, chart type, and price plot
# barbaros - v4  - 2021/03/02 - added trade time limit and do not cross before start time
# barbaros - v5  - 2021/03/02 - added direction label
# barbaros - v6  - 2021/03/03 - added alerts, exit at profit delta, arrows for exiting position, and changed defaults to show all
# barbaros - v7  - 2021/03/03 - removed inputs for disabling arrows - this can be done in ToS already,
#                              added profit target line, ExitAt selection and ATR target
# barbaros - v8  - 2021/03/05 - added profit target label, changed the exit strategy to high/low instead of close
# barbaros - v9  - 2021/03/06 - added entry price label
# barbaros - v10 - 2021/03/11 - trying to fix before 9:40am EST crossing filter
# barbaros - v11 - 2021/03/11 - removed chart type overwriting
# barbaros - v12 - 2021/03/11 - fixed issue with disabling DoNotCrossBeforeStart
# barbaros - v13 - 2021/03/12 - fixed issue with macdonly win counting
# barbaros - v14 - 2021/03/13 - added PnL and ROI - note: only /ES margin is available
# barbaros - v15 - 2021/03/14 - added PnL bubbles option, ROI label hiding, and tweaks to PnL

# Setup
# 10 Min chart
# Heikin Ashi candles
# SMA 3/9
# MACD Bollinger Bands (the one Ben has posted on here a while back) 8,16,36 and uncheck "show plot" on the BB upper, BB lower and BB mid line. You will only be using the zero line, MACD dots and MACD Line for entry purposes. The inputs of "b length" and "bb num dev" are irrelevant here since you will remove the the plots that I mentioned.
# ErgodicOsc 2,10,36 (changed the default negative to red)

# Option call logic:
# 1. The SMA's have to cross first.
# 2. For a call opportunity, you will then wait to see if the MACD dots cross above the MACD zero line. Its critical here to wait until one dot has cleared the zero line...you MUST see a gap....never enter with the dot on the line. Dots must be consistent as well...if its going up...then they must all be white...if a red dot populates between the time a white dot hits the zero line and the time one crosses clear....don't enter. I have a screenshot below showing this example - 13:00 a red dot appears.
# 3. The ErgodicOsc HAS to be green when the MACD dot crosses above the zero line. You can hold the trade most of the time until this turns from green to red....but I always set a sell limit just in case it whips back in the opposite direction.

# Option put logic:
# Obviously its the complete opposite of what I've described above for a call. BUT - the SMA's still have to cross first.

# Note:
# Historical price action testing shows that if the MACDBB crosses zerobase before 9:40 EST, do not take the trade. Also, there might be too much choppiness after 15:00 EST.

declare upper;

input AllowNonSPX = no;
input ShowLabels = yes;
input ShowStatistics = yes;
input ShowROI = yes;
input ShowPnLBubbles = no;
input ExitAt = {default "profitDeltaOrMACD", "MACDOnly", "ATRorMACD"};
input ProfitDelta = 1.0;
input ATRLength = 7.0;
input ATRMult = 0.5;
input LimitTime = yes;
input StartTime = 940;
input StopTime = 1500;
input DoNotCrossBeforeStart = yes;

input price = close;
input SMAFastLength = 3;
input SMASlowLength = 9;
input BBlength = 30;
input BBNum_Dev = 0.8;
input BBCrossInBars = 3;
input BBCrossDistance = 1.0;
input MACDfastLength = 8;
input MACDslowLength = 16;
input MACDLength = 36;
input ERGODICLongLength = 2;
input ERGODICShortLength = 10;
input ERGODICSignalLength = 36;
input ERGODICAverageType = {"SIMPLE", default "EXPONENTIAL", "WEIGHTED", "WILDERS", "HULL"};

# Check for 10min chart
Assert(AllowNonSPX or GetAggregationPeriod() == AggregationPeriod.TEN_MIN, "Incorrect Chart Time, use 10m");
Assert(AllowNonSPX or GetSymbol() == "SPX", "Incorrect Chart Time, use 10m");

# MACD
def MACD_Data = MACD(fastLength = MACDfastLength, slowLength = MACDslowLength, MACDLength = MACDLength);
def MACD_Direction = if MACD_Data > MACD_Data[1] then 1 else -1;
def MACD_CrossBar = if MACD_Data crosses above 0 within 1 bar or MACD_Data crosses below 0 within 1 bar then BarNumber() else MACD_CrossBar[1];
def MACD_CrossBarAgo = BarNumber() - MACD_CrossBar;

# Ergodic
def Ergodic_Data = ErgodicOsc("long length" = ERGODICLongLength, "short length" = ERGODICShortLength, "signal length" = ERGODICSignalLength, "average type" = ERGODICAverageType).ErgodicOsc;

# SMAs
def SMA_Fast = SimpleMovingAvg(price, SMAFastLength);
def SMA_Slow = SimpleMovingAvg(price, SMASlowLength);

# ATR for progit target
def atrDelta = ATR(ATRLength) * ATRMult;

# Time Limit
def isTradeTime = if LimitTime then SecondsFromTime(StartTime) >= 0 and SecondsTillTime(StopTime) >= 0 else yes;
def isNotCrossBeforeStart = if !DoNotCrossBeforeStart then yes
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) == 0 and MACD_CrossBarAgo == 1 then no
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) != 0 and MACD_CrossBar[1] != MACD_CrossBar then yes
                            else isNotCrossBeforeStart[1];

# Signals
def buySignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_Data >= BBCrossDistance and MACD_Data crosses above 0 within BBCrossInBars bars;
def buyWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_CrossBar[1] != MACD_CrossBar;

def sellSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_Data <= -BBCrossDistance and MACD_Data crosses below 0 within BBCrossInBars bars;
def sellWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_CrossBar[1] != MACD_CrossBar;

# Plots
plot buy = buySignal and !buySignal[1];
buy.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buy.setDefaultColor(Color.GREEN);
buy.setLineWeight(3);

plot buyWarn = buyWarnSignal and !buyWarnSignal[1];
buyWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buyWarn.setDefaultColor(Color.CYAN);
buyWarn.setLineWeight(1);

plot sell = sellSignal and !sellSignal[1];
sell.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sell.setDefaultColor(Color.RED);
sell.setLineWeight(3);

plot sellWarn = sellWarnSignal and !sellWarnSignal[1];
sellWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sellWarn.setDefaultColor(Color.MAGENTA);
sellWarn.setLineWeight(1);

plot lastPrice = price;
lastPrice.setPaintingStrategy(PaintingStrategy.POINTS);
lastPrice.setDefaultColor(Color.GREEN);

plot fast = SMA_Fast;
fast.setPaintingStrategy(PaintingStrategy.LINE);
fast.setDefaultColor(Color.CYAN);
fast.setLineWeight(1);

plot slow = SMA_Slow;
slow.setPaintingStrategy(PaintingStrategy.LINE);
slow.setDefaultColor(Color.MAGENTA);
slow.setLineWeight(1);

# PnL
def entryPrice = if (buySignal and !buySignal[1]) or (sellSignal and !sellSignal[1]) then open[-1] else entryPrice[1];
def profitDeltaTarget = if ExitAt == ExitAt.profitDeltaOrMACD then ProfitDelta else if ExitAt == ExitAt.ATRorMACD then atrDelta else 0;
def profitTarget = if buySignal and !buySignal[1] then entryPrice + profitDeltaTarget
                   else if sellSignal and !sellSignal[1] then entryPrice - profitDeltaTarget
                   else profitTarget[1];
def orderDir = if BarNumber() == 1 then 0
               else if orderDir[1] == 0 and buySignal and !buySignal[1] then 1
               else if orderDir[1] == 1 and (MACD_Direction != 1 or (ExitAt != ExitAt.MACDOnly and high >= profitTarget)) then 0
               else if orderDir[1] == 0 and sellSignal and !sellSignal[1] then -1
               else if orderDir[1] == -1 and (MACD_Direction != -1 or (ExitAt != ExitAt.MACDOnly and low <= profitTarget)) then 0
               else orderDir[1];

def isOrder = if IsNaN(orderDir) then no else orderDir crosses 0;
def orderCount = CompoundValue(1, if IsNaN(isOrder) then 0 else if isOrder then orderCount[1] + 1 else orderCount[1], 0);

def orderWinners = if BarNumber() == 1 then 0
                    else if orderDir[1] == 1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) or (close > entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else if orderDir[1] == -1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) or (close < entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else orderWinners[1];
def winRate = orderWinners / orderCount;

def PnL = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
            if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) then PnL[1] + ((profitTarget[1] - entryPrice[1]) * TickValue())
            else PnL[1] + ((close - entryPrice) * TickValue())
           else if orderDir[1] == -1 and orderDir == 0 then
             if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) then PnL[1] + ((entryPrice[1] - profitTarget[1]) * TickValue())
             else PnL[1] + ((entryPrice - close) * TickValue())
           else PnL[1];

def costPrice = if GetSymbol() == "/ES:XCME" then 13000
                else entryPrice;
def ROI = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
                 ROI[1] + (((close - entryPrice) * TickValue())/costPrice)
           else if orderDir[1] == -1 and orderDir == 0 then
               ROI[1] + (((entryPrice - close) * TickValue())/costPrice)
           else ROI[1];

# Plot Exit Positions
plot buyExit = orderDir[1] == 1 and orderDir != 1;
buyExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
buyExit.setDefaultColor(Color.GREEN);
buyExit.setLineWeight(3);

plot sellExit = orderDir[1] == -1 and orderDir != -1;
sellExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
sellExit.setDefaultColor(Color.RED);
sellExit.setLineWeight(3);

plot profitTargetLevel = if orderDir != 0 or orderDir[1] != 0 then profitTarget else Double.NaN;
profitTargetLevel.setPaintingStrategy(PaintingStrategy.LINE);
profitTargetLevel.setDefaultColor(Color.GREEN);
profitTargetLevel.setLineWeight(3);

# Labels
AddLabel(ShowLabels, "SPX Strategy", Color.WHITE);
AddLabel(ShowLabels, if buy then "Buy"
                     else if sell then "Sell"
                     else if buyWarn or sellWarn then "Warn"
                     else if orderDir == 1 then "Long"
                     else if orderDir == -1 then "Short"
                     else "Neutral",
                     if buy then Color.GREEN
                     else if sell then Color.RED
                     else if buyWarn then Color.YELLOW
                     else if sellWarn then Color.LIGHT_RED
                     else if orderDir == 1 then Color.YELLOW
                     else if orderDir == -1 then Color.LIGHT_RED
                     else Color.GRAY
);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(entryPrice), "Entry " + AsDollars(entryPrice), Color.GRAY);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(profitTarget), "Target " + AsDollars(profitTarget), Color.GRAY);
AddLabel(ShowLabels and ShowStatistics, "" + orderCount + " Trades | " + AsPercent(winRate), if winRate > 0.5 then Color.GREEN else Color.RED);
AddLabel(ShowLabels and ShowROI, "" + AsDollars(PnL) + " | " + AsPercent(ROI), if ROI > 0 then Color.GREEN else Color.RED);

AddChartBubble(ShowPnLBubbles and orderDir == 0 and orderDir[1] != 0, close, AsDollars(PnL) + " (" + AsDollars(PnL - PnL[1]) + ")", Color.WHITE);

# Alerts
Alert(buy, "Buy", Alert.BAR, Sound.Ring);
Alert(sell, "Sell", Alert.BAR, Sound.Ring);
Alert(buyWarn, "Buy Warning", Alert.BAR, Sound.Ding);
Alert(sellWarn, "Sell Warning", Alert.BAR, Sound.Ding);
Alert(buyExit, "Buy Exit", Alert.BAR, Sound.Ring);
Alert(sellExit, "Sell Exit", Alert.BAR, Sound.Ring);
 
another update...

Python:
# SPX Strategy
# Strategy designed by Hypoluxa
# barbaros - v1  - 2021/02/25
# barbaros - v2  - 2021/02/25 - added warning arrows, alerts, statistics and non SPX trading option
# barbaros - v3  - 2021/02/26 - added SMA plots, chart type, and price plot
# barbaros - v4  - 2021/03/02 - added trade time limit and do not cross before start time
# barbaros - v5  - 2021/03/02 - added direction label
# barbaros - v6  - 2021/03/03 - added alerts, exit at profit delta, arrows for exiting position, and changed defaults to show all
# barbaros - v7  - 2021/03/03 - removed inputs for disabling arrows - this can be done in ToS already,
#                              added profit target line, ExitAt selection and ATR target
# barbaros - v8  - 2021/03/05 - added profit target label, changed the exit strategy to high/low instead of close
# barbaros - v9  - 2021/03/06 - added entry price label
# barbaros - v10 - 2021/03/11 - trying to fix before 9:40am EST crossing filter
# barbaros - v11 - 2021/03/11 - removed chart type overwriting
# barbaros - v12 - 2021/03/11 - fixed issue with disabling DoNotCrossBeforeStart
# barbaros - v13 - 2021/03/12 - fixed issue with macdonly win counting
# barbaros - v14 - 2021/03/13 - added PnL and ROI - note: only /ES margin is available
# barbaros - v15 - 2021/03/14 - added PnL bubbles option, ROI label hiding, and tweaks to PnL
# barbaros - v16 - 2021/03/14 - PnL bubble coloring, fixed an issue with futures PnL values

# Setup
# 10 Min chart
# Heikin Ashi candles
# SMA 3/9
# MACD Bollinger Bands (the one Ben has posted on here a while back) 8,16,36 and uncheck "show plot" on the BB upper, BB lower and BB mid line. You will only be using the zero line, MACD dots and MACD Line for entry purposes. The inputs of "b length" and "bb num dev" are irrelevant here since you will remove the the plots that I mentioned.
# ErgodicOsc 2,10,36 (changed the default negative to red)

# Option call logic:
# 1. The SMA's have to cross first.
# 2. For a call opportunity, you will then wait to see if the MACD dots cross above the MACD zero line. Its critical here to wait until one dot has cleared the zero line...you MUST see a gap....never enter with the dot on the line. Dots must be consistent as well...if its going up...then they must all be white...if a red dot populates between the time a white dot hits the zero line and the time one crosses clear....don't enter. I have a screenshot below showing this example - 13:00 a red dot appears.
# 3. The ErgodicOsc HAS to be green when the MACD dot crosses above the zero line. You can hold the trade most of the time until this turns from green to red....but I always set a sell limit just in case it whips back in the opposite direction.

# Option put logic:
# Obviously its the complete opposite of what I've described above for a call. BUT - the SMA's still have to cross first.

# Note:
# Historical price action testing shows that if the MACDBB crosses zerobase before 9:40 EST, do not take the trade. Also, there might be too much choppiness after 15:00 EST.

declare upper;

input AllowNonSPX = no;
input ShowLabels = yes;
input ShowStatistics = yes;
input ShowROI = yes;
input ShowPnLBubbles = no;
input ExitAt = {default "profitDeltaOrMACD", "MACDOnly", "ATRorMACD"};
input ProfitDelta = 1.0;
input ATRLength = 7.0;
input ATRMult = 0.5;
input LimitTime = yes;
input StartTime = 940;
input StopTime = 1500;
input DoNotCrossBeforeStart = yes;

input price = close;
input SMAFastLength = 3;
input SMASlowLength = 9;
input BBlength = 30;
input BBNum_Dev = 0.8;
input BBCrossInBars = 3;
input BBCrossDistance = 1.0;
input MACDfastLength = 8;
input MACDslowLength = 16;
input MACDLength = 36;
input ERGODICLongLength = 2;
input ERGODICShortLength = 10;
input ERGODICSignalLength = 36;
input ERGODICAverageType = {"SIMPLE", default "EXPONENTIAL", "WEIGHTED", "WILDERS", "HULL"};

# Check for 10min chart
Assert(AllowNonSPX or GetAggregationPeriod() == AggregationPeriod.TEN_MIN, "Incorrect Chart Time, use 10m");
Assert(AllowNonSPX or GetSymbol() == "SPX", "Incorrect Chart Time, use 10m");

# MACD
def MACD_Data = MACD(fastLength = MACDfastLength, slowLength = MACDslowLength, MACDLength = MACDLength);
def MACD_Direction = if MACD_Data > MACD_Data[1] then 1 else -1;
def MACD_CrossBar = if MACD_Data crosses above 0 within 1 bar or MACD_Data crosses below 0 within 1 bar then BarNumber() else MACD_CrossBar[1];
def MACD_CrossBarAgo = BarNumber() - MACD_CrossBar;

# Ergodic
def Ergodic_Data = ErgodicOsc("long length" = ERGODICLongLength, "short length" = ERGODICShortLength, "signal length" = ERGODICSignalLength, "average type" = ERGODICAverageType).ErgodicOsc;

# SMAs
def SMA_Fast = SimpleMovingAvg(price, SMAFastLength);
def SMA_Slow = SimpleMovingAvg(price, SMASlowLength);

# ATR for progit target
def atrDelta = ATR(ATRLength) * ATRMult;

# Time Limit
def isTradeTime = if LimitTime then SecondsFromTime(StartTime) >= 0 and SecondsTillTime(StopTime) >= 0 else yes;
def isNotCrossBeforeStart = if !DoNotCrossBeforeStart then yes
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) == 0 and MACD_CrossBarAgo == 1 then no
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) != 0 and MACD_CrossBar[1] != MACD_CrossBar then yes
                            else isNotCrossBeforeStart[1];

# Signals
def buySignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_Data >= BBCrossDistance and MACD_Data crosses above 0 within BBCrossInBars bars;
def buyWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_CrossBar[1] != MACD_CrossBar;

def sellSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_Data <= -BBCrossDistance and MACD_Data crosses below 0 within BBCrossInBars bars;
def sellWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_CrossBar[1] != MACD_CrossBar;

# Plots
plot buy = buySignal and !buySignal[1];
buy.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buy.setDefaultColor(Color.GREEN);
buy.setLineWeight(3);

plot buyWarn = buyWarnSignal and !buyWarnSignal[1];
buyWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buyWarn.setDefaultColor(Color.CYAN);
buyWarn.setLineWeight(1);

plot sell = sellSignal and !sellSignal[1];
sell.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sell.setDefaultColor(Color.RED);
sell.setLineWeight(3);

plot sellWarn = sellWarnSignal and !sellWarnSignal[1];
sellWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sellWarn.setDefaultColor(Color.MAGENTA);
sellWarn.setLineWeight(1);

plot lastPrice = price;
lastPrice.setPaintingStrategy(PaintingStrategy.POINTS);
lastPrice.setDefaultColor(Color.GREEN);

plot fast = SMA_Fast;
fast.setPaintingStrategy(PaintingStrategy.LINE);
fast.setDefaultColor(Color.CYAN);
fast.setLineWeight(1);

plot slow = SMA_Slow;
slow.setPaintingStrategy(PaintingStrategy.LINE);
slow.setDefaultColor(Color.MAGENTA);
slow.setLineWeight(1);

# PnL
def entryPrice = if (buySignal and !buySignal[1]) or (sellSignal and !sellSignal[1]) then open[-1] else entryPrice[1];
def profitDeltaTarget = if ExitAt == ExitAt.profitDeltaOrMACD then ProfitDelta else if ExitAt == ExitAt.ATRorMACD then atrDelta else 0;
def profitTarget = if buySignal and !buySignal[1] then entryPrice + profitDeltaTarget
                   else if sellSignal and !sellSignal[1] then entryPrice - profitDeltaTarget
                   else profitTarget[1];
def orderDir = if BarNumber() == 1 then 0
               else if orderDir[1] == 0 and buySignal and !buySignal[1] then 1
               else if orderDir[1] == 1 and (MACD_Direction != 1 or (ExitAt != ExitAt.MACDOnly and high >= profitTarget)) then 0
               else if orderDir[1] == 0 and sellSignal and !sellSignal[1] then -1
               else if orderDir[1] == -1 and (MACD_Direction != -1 or (ExitAt != ExitAt.MACDOnly and low <= profitTarget)) then 0
               else orderDir[1];

def isOrder = if IsNaN(orderDir) then no else orderDir crosses 0;
def orderCount = CompoundValue(1, if IsNaN(isOrder) then 0 else if isOrder then orderCount[1] + 1 else orderCount[1], 0);

def orderWinners = if BarNumber() == 1 then 0
                    else if orderDir[1] == 1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) or (close > entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else if orderDir[1] == -1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) or (close < entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else orderWinners[1];
def winRate = orderWinners / orderCount;

def PnL = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
            if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) then PnL[1] + (((profitTarget[1] - entryPrice[1])/TickSize()) * TickValue())
            else PnL[1] + (((close - entryPrice)/TickSize()) * TickValue())
           else if orderDir[1] == -1 and orderDir == 0 then
             if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) then PnL[1] + (((entryPrice[1] - profitTarget[1])/TickSize()) * TickValue())
             else PnL[1] + (((entryPrice - close)/TickSize()) * TickValue())
           else PnL[1];

def costPrice = if GetSymbol() == "/ES:XCME" then 13000
                else entryPrice;
def ROI = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
                 ROI[1] + ((PnL - PnL[1])/costPrice)
           else if orderDir[1] == -1 and orderDir == 0 then
               ROI[1] + ((PnL - PnL[1])/costPrice)
           else ROI[1];

# Plot Exit Positions
plot buyExit = orderDir[1] == 1 and orderDir != 1;
buyExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
buyExit.setDefaultColor(Color.GREEN);
buyExit.setLineWeight(3);

plot sellExit = orderDir[1] == -1 and orderDir != -1;
sellExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
sellExit.setDefaultColor(Color.RED);
sellExit.setLineWeight(3);

plot profitTargetLevel = if orderDir != 0 or orderDir[1] != 0 then profitTarget else Double.NaN;
profitTargetLevel.setPaintingStrategy(PaintingStrategy.LINE);
profitTargetLevel.setDefaultColor(Color.GREEN);
profitTargetLevel.setLineWeight(3);

# Labels
AddLabel(ShowLabels, "SPX Strategy", Color.WHITE);
AddLabel(ShowLabels, if buy then "Buy"
                     else if sell then "Sell"
                     else if buyWarn or sellWarn then "Warn"
                     else if orderDir == 1 then "Long"
                     else if orderDir == -1 then "Short"
                     else "Neutral",
                     if buy then Color.GREEN
                     else if sell then Color.RED
                     else if buyWarn then Color.YELLOW
                     else if sellWarn then Color.LIGHT_RED
                     else if orderDir == 1 then Color.YELLOW
                     else if orderDir == -1 then Color.LIGHT_RED
                     else Color.GRAY
);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(entryPrice), "Entry " + AsDollars(entryPrice), Color.GRAY);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(profitTarget), "Target " + AsDollars(profitTarget), Color.GRAY);
AddLabel(ShowLabels and ShowStatistics, "" + orderCount + " Trades | " + AsPercent(winRate), if winRate > 0.5 then Color.GREEN else Color.RED);
AddLabel(ShowLabels and ShowROI, "" + AsDollars(PnL) + " | " + AsPercent(ROI), if ROI > 0 then Color.GREEN else Color.RED);

AddChartBubble(ShowPnLBubbles and orderDir == 0 and orderDir[1] != 0, close, AsDollars(PnL) + " (" + AsDollars(PnL - PnL[1]) + ")", if (PnL - PnL[1]) > 0 then Color.GREEN else Color.RED);

# Alerts
Alert(buy, "Buy", Alert.BAR, Sound.Ring);
Alert(sell, "Sell", Alert.BAR, Sound.Ring);
Alert(buyWarn, "Buy Warning", Alert.BAR, Sound.Ding);
Alert(sellWarn, "Sell Warning", Alert.BAR, Sound.Ding);
Alert(buyExit, "Buy Exit", Alert.BAR, Sound.Ring);
Alert(sellExit, "Sell Exit", Alert.BAR, Sound.Ring);
 
Just wanted to make sure again, this is just the buy warning right? If somebody got into the trade they might lost the play. I saw few post that some guys are buying at warning. But this one seem bit tricky as it fulfilled all the requirements to go all in. I know there is not a 100% play but just posting if anybody saw this and have any thoughts?


dQorfCb.jpg
 
Just wanted to make sure again, this is just the buy warning right? If somebody got into the trade they might lost the play. I saw few post that some guys are buying at warning. But this one seem bit tricky as it fulfilled all the requirements to go all in. I know there is not a 100% play but just posting if anybody saw this and have any thoughts?


dQorfCb.jpg
That is a buy warning and not a buy confirmation
 
It is completely possible to have a higher win rate but less profit. I used 3pt target for profitdeltaormacg option and it is less of a profit than 1pt target. This is because when you set 3pt, it has such a large loss that small increments don't catch up.

You will need to tune your strategy to your risk as @Hypoluxa said many times. There isn't a specific stoploss for this strategy. I personally use resistance and support levels to determine entries and exists with assistance of this indicator.

This version might help you visualize better. I also made a few more tweaks. You can enable "ShowPnLBubbles" to see how the PnL changes over the chart time.

Let me know what you find.

Python:
# SPX Strategy
# Strategy designed by Hypoluxa
# barbaros - v1  - 2021/02/25
# barbaros - v2  - 2021/02/25 - added warning arrows, alerts, statistics and non SPX trading option
# barbaros - v3  - 2021/02/26 - added SMA plots, chart type, and price plot
# barbaros - v4  - 2021/03/02 - added trade time limit and do not cross before start time
# barbaros - v5  - 2021/03/02 - added direction label
# barbaros - v6  - 2021/03/03 - added alerts, exit at profit delta, arrows for exiting position, and changed defaults to show all
# barbaros - v7  - 2021/03/03 - removed inputs for disabling arrows - this can be done in ToS already,
#                              added profit target line, ExitAt selection and ATR target
# barbaros - v8  - 2021/03/05 - added profit target label, changed the exit strategy to high/low instead of close
# barbaros - v9  - 2021/03/06 - added entry price label
# barbaros - v10 - 2021/03/11 - trying to fix before 9:40am EST crossing filter
# barbaros - v11 - 2021/03/11 - removed chart type overwriting
# barbaros - v12 - 2021/03/11 - fixed issue with disabling DoNotCrossBeforeStart
# barbaros - v13 - 2021/03/12 - fixed issue with macdonly win counting
# barbaros - v14 - 2021/03/13 - added PnL and ROI - note: only /ES margin is available
# barbaros - v15 - 2021/03/14 - added PnL bubbles option, ROI label hiding, and tweaks to PnL

# Setup
# 10 Min chart
# Heikin Ashi candles
# SMA 3/9
# MACD Bollinger Bands (the one Ben has posted on here a while back) 8,16,36 and uncheck "show plot" on the BB upper, BB lower and BB mid line. You will only be using the zero line, MACD dots and MACD Line for entry purposes. The inputs of "b length" and "bb num dev" are irrelevant here since you will remove the the plots that I mentioned.
# ErgodicOsc 2,10,36 (changed the default negative to red)

# Option call logic:
# 1. The SMA's have to cross first.
# 2. For a call opportunity, you will then wait to see if the MACD dots cross above the MACD zero line. Its critical here to wait until one dot has cleared the zero line...you MUST see a gap....never enter with the dot on the line. Dots must be consistent as well...if its going up...then they must all be white...if a red dot populates between the time a white dot hits the zero line and the time one crosses clear....don't enter. I have a screenshot below showing this example - 13:00 a red dot appears.
# 3. The ErgodicOsc HAS to be green when the MACD dot crosses above the zero line. You can hold the trade most of the time until this turns from green to red....but I always set a sell limit just in case it whips back in the opposite direction.

# Option put logic:
# Obviously its the complete opposite of what I've described above for a call. BUT - the SMA's still have to cross first.

# Note:
# Historical price action testing shows that if the MACDBB crosses zerobase before 9:40 EST, do not take the trade. Also, there might be too much choppiness after 15:00 EST.

declare upper;

input AllowNonSPX = no;
input ShowLabels = yes;
input ShowStatistics = yes;
input ShowROI = yes;
input ShowPnLBubbles = no;
input ExitAt = {default "profitDeltaOrMACD", "MACDOnly", "ATRorMACD"};
input ProfitDelta = 1.0;
input ATRLength = 7.0;
input ATRMult = 0.5;
input LimitTime = yes;
input StartTime = 940;
input StopTime = 1500;
input DoNotCrossBeforeStart = yes;

input price = close;
input SMAFastLength = 3;
input SMASlowLength = 9;
input BBlength = 30;
input BBNum_Dev = 0.8;
input BBCrossInBars = 3;
input BBCrossDistance = 1.0;
input MACDfastLength = 8;
input MACDslowLength = 16;
input MACDLength = 36;
input ERGODICLongLength = 2;
input ERGODICShortLength = 10;
input ERGODICSignalLength = 36;
input ERGODICAverageType = {"SIMPLE", default "EXPONENTIAL", "WEIGHTED", "WILDERS", "HULL"};

# Check for 10min chart
Assert(AllowNonSPX or GetAggregationPeriod() == AggregationPeriod.TEN_MIN, "Incorrect Chart Time, use 10m");
Assert(AllowNonSPX or GetSymbol() == "SPX", "Incorrect Chart Time, use 10m");

# MACD
def MACD_Data = MACD(fastLength = MACDfastLength, slowLength = MACDslowLength, MACDLength = MACDLength);
def MACD_Direction = if MACD_Data > MACD_Data[1] then 1 else -1;
def MACD_CrossBar = if MACD_Data crosses above 0 within 1 bar or MACD_Data crosses below 0 within 1 bar then BarNumber() else MACD_CrossBar[1];
def MACD_CrossBarAgo = BarNumber() - MACD_CrossBar;

# Ergodic
def Ergodic_Data = ErgodicOsc("long length" = ERGODICLongLength, "short length" = ERGODICShortLength, "signal length" = ERGODICSignalLength, "average type" = ERGODICAverageType).ErgodicOsc;

# SMAs
def SMA_Fast = SimpleMovingAvg(price, SMAFastLength);
def SMA_Slow = SimpleMovingAvg(price, SMASlowLength);

# ATR for progit target
def atrDelta = ATR(ATRLength) * ATRMult;

# Time Limit
def isTradeTime = if LimitTime then SecondsFromTime(StartTime) >= 0 and SecondsTillTime(StopTime) >= 0 else yes;
def isNotCrossBeforeStart = if !DoNotCrossBeforeStart then yes
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) == 0 and MACD_CrossBarAgo == 1 then no
                            else if DoNotCrossBeforeStart and SecondsFromTime(StartTime) != 0 and MACD_CrossBar[1] != MACD_CrossBar then yes
                            else isNotCrossBeforeStart[1];

# Signals
def buySignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_Data >= BBCrossDistance and MACD_Data crosses above 0 within BBCrossInBars bars;
def buyWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast > SMA_Slow and Ergodic_Data > 0 and MACD_Direction == 1 and MACD_CrossBar[1] != MACD_CrossBar;

def sellSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_Data <= -BBCrossDistance and MACD_Data crosses below 0 within BBCrossInBars bars;
def sellWarnSignal = isTradeTime and isNotCrossBeforeStart and SMA_Fast < SMA_Slow and Ergodic_Data < 0 and MACD_Direction == -1 and MACD_CrossBar[1] != MACD_CrossBar;

# Plots
plot buy = buySignal and !buySignal[1];
buy.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buy.setDefaultColor(Color.GREEN);
buy.setLineWeight(3);

plot buyWarn = buyWarnSignal and !buyWarnSignal[1];
buyWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
buyWarn.setDefaultColor(Color.CYAN);
buyWarn.setLineWeight(1);

plot sell = sellSignal and !sellSignal[1];
sell.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sell.setDefaultColor(Color.RED);
sell.setLineWeight(3);

plot sellWarn = sellWarnSignal and !sellWarnSignal[1];
sellWarn.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
sellWarn.setDefaultColor(Color.MAGENTA);
sellWarn.setLineWeight(1);

plot lastPrice = price;
lastPrice.setPaintingStrategy(PaintingStrategy.POINTS);
lastPrice.setDefaultColor(Color.GREEN);

plot fast = SMA_Fast;
fast.setPaintingStrategy(PaintingStrategy.LINE);
fast.setDefaultColor(Color.CYAN);
fast.setLineWeight(1);

plot slow = SMA_Slow;
slow.setPaintingStrategy(PaintingStrategy.LINE);
slow.setDefaultColor(Color.MAGENTA);
slow.setLineWeight(1);

# PnL
def entryPrice = if (buySignal and !buySignal[1]) or (sellSignal and !sellSignal[1]) then open[-1] else entryPrice[1];
def profitDeltaTarget = if ExitAt == ExitAt.profitDeltaOrMACD then ProfitDelta else if ExitAt == ExitAt.ATRorMACD then atrDelta else 0;
def profitTarget = if buySignal and !buySignal[1] then entryPrice + profitDeltaTarget
                   else if sellSignal and !sellSignal[1] then entryPrice - profitDeltaTarget
                   else profitTarget[1];
def orderDir = if BarNumber() == 1 then 0
               else if orderDir[1] == 0 and buySignal and !buySignal[1] then 1
               else if orderDir[1] == 1 and (MACD_Direction != 1 or (ExitAt != ExitAt.MACDOnly and high >= profitTarget)) then 0
               else if orderDir[1] == 0 and sellSignal and !sellSignal[1] then -1
               else if orderDir[1] == -1 and (MACD_Direction != -1 or (ExitAt != ExitAt.MACDOnly and low <= profitTarget)) then 0
               else orderDir[1];

def isOrder = if IsNaN(orderDir) then no else orderDir crosses 0;
def orderCount = CompoundValue(1, if IsNaN(isOrder) then 0 else if isOrder then orderCount[1] + 1 else orderCount[1], 0);

def orderWinners = if BarNumber() == 1 then 0
                    else if orderDir[1] == 1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) or (close > entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else if orderDir[1] == -1 and orderDir == 0 then
                        if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) or (close < entryPrice) then orderWinners[1] + 1 else orderWinners[1]
                    else orderWinners[1];
def winRate = orderWinners / orderCount;

def PnL = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
            if (ExitAt != ExitAt.MACDOnly and high >= profitTarget[1]) then PnL[1] + ((profitTarget[1] - entryPrice[1]) * TickValue())
            else PnL[1] + ((close - entryPrice) * TickValue())
           else if orderDir[1] == -1 and orderDir == 0 then
             if (ExitAt != ExitAt.MACDOnly and low <= profitTarget[1]) then PnL[1] + ((entryPrice[1] - profitTarget[1]) * TickValue())
             else PnL[1] + ((entryPrice - close) * TickValue())
           else PnL[1];

def costPrice = if GetSymbol() == "/ES:XCME" then 13000
                else entryPrice;
def ROI = if BarNumber() == 1 then 0
           else if orderDir[1] == 1 and orderDir == 0 then
                 ROI[1] + (((close - entryPrice) * TickValue())/costPrice)
           else if orderDir[1] == -1 and orderDir == 0 then
               ROI[1] + (((entryPrice - close) * TickValue())/costPrice)
           else ROI[1];

# Plot Exit Positions
plot buyExit = orderDir[1] == 1 and orderDir != 1;
buyExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
buyExit.setDefaultColor(Color.GREEN);
buyExit.setLineWeight(3);

plot sellExit = orderDir[1] == -1 and orderDir != -1;
sellExit.setPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
sellExit.setDefaultColor(Color.RED);
sellExit.setLineWeight(3);

plot profitTargetLevel = if orderDir != 0 or orderDir[1] != 0 then profitTarget else Double.NaN;
profitTargetLevel.setPaintingStrategy(PaintingStrategy.LINE);
profitTargetLevel.setDefaultColor(Color.GREEN);
profitTargetLevel.setLineWeight(3);

# Labels
AddLabel(ShowLabels, "SPX Strategy", Color.WHITE);
AddLabel(ShowLabels, if buy then "Buy"
                     else if sell then "Sell"
                     else if buyWarn or sellWarn then "Warn"
                     else if orderDir == 1 then "Long"
                     else if orderDir == -1 then "Short"
                     else "Neutral",
                     if buy then Color.GREEN
                     else if sell then Color.RED
                     else if buyWarn then Color.YELLOW
                     else if sellWarn then Color.LIGHT_RED
                     else if orderDir == 1 then Color.YELLOW
                     else if orderDir == -1 then Color.LIGHT_RED
                     else Color.GRAY
);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(entryPrice), "Entry " + AsDollars(entryPrice), Color.GRAY);
AddLabel(ShowLabels and orderDir != 0 and !isNaN(profitTarget), "Target " + AsDollars(profitTarget), Color.GRAY);
AddLabel(ShowLabels and ShowStatistics, "" + orderCount + " Trades | " + AsPercent(winRate), if winRate > 0.5 then Color.GREEN else Color.RED);
AddLabel(ShowLabels and ShowROI, "" + AsDollars(PnL) + " | " + AsPercent(ROI), if ROI > 0 then Color.GREEN else Color.RED);

AddChartBubble(ShowPnLBubbles and orderDir == 0 and orderDir[1] != 0, close, AsDollars(PnL) + " (" + AsDollars(PnL - PnL[1]) + ")", Color.WHITE);

# Alerts
Alert(buy, "Buy", Alert.BAR, Sound.Ring);
Alert(sell, "Sell", Alert.BAR, Sound.Ring);
Alert(buyWarn, "Buy Warning", Alert.BAR, Sound.Ding);
Alert(sellWarn, "Sell Warning", Alert.BAR, Sound.Ding);
Alert(buyExit, "Buy Exit", Alert.BAR, Sound.Ring);
Alert(sellExit, "Sell Exit", Alert.BAR, Sound.Ring);
Thanks for responding. Another idea I've been pondering is quite interesting, and @Hypoluxa has mentioned a part of it a couple of times here. Essentially, this system is quite good, but things usually seem to go the opposite direction, usually temporarily and sometimes significantly, before they reverse and go in the desired direction again. As a result, I'm thinking of doing as follows:

1. As @Hypoluxa has advised, waiting for the initial opposite movement and then getting in at a better price before it reverses, ideally with a stop buy above the now dropped price so that we're not catching knives.

2. Or perhaps we could try to buy the signal candle 1 minute before it closes, although it could always move opposite in the last minute as well, so maybe this is not ideal. I don't know.

3. Another option that appeals to me is setting a stop buy a few ticks (or even a point or more depending on experience) above the close of the signal candle. This way, we enter the trade only if and when it reverses course and goes in the desired direction. Winning momemtum is built into this approach, although obviously nothing is guaranteed.

We don't necessarily need any of this coded into the study to guide our trades. The study does a fine job of providing signals we can act on with good judgment. However, for purposes of winrate, P/L, and backtesting, coding this would provide a clearer picture of the strat's effectiveness.

I assume #3 is the easiest and most practical entry to code because it's a clear mechanical formula, adding a set tick number to previous candle's close. The number of ticks/points could be a user selected option, customizable to their preferences (especially because each stock/futures has different volatility).

Approach #1 above has the most upside, if we could set a stop buy above the price drop, but I assume it's more tricky because we don't know how much it will drop before it bounces back. So how could that be coded, if it can at all? One possible option is to take a set number of ticks (again, can be user determined in option) where it drops that many ticks from open, then the stop buy would go 2 or 3 ticks above. So, for example, we can set it to a 6 tick drop assumption and calculate entry 3 ticks above that. However, I'm not sure we could actually act on that in real time anyway. ES might move too fast to do all that.

I just wanted to share my thought process to see if there's any way to improve this wonderful study.
 
It’s probably better to separate the indicator and backtesting tool to test these. There is strategy type in ToS that handles order management for backtesting. We would be replicating that in the indicator but almost there anyway. All can be done, but will take time.
 
yes it is ninjatrader.. i havent been running it for a long time... only after i read about it here... i run 2 c usually first contract i scalp for 12 ticks and second one i stay in it until macd turns down... here are the results for the last 30 days (backtest and not real trades) so take it with a grain of salt.

I am trying to do the same in NT, but finding issues. Would you mind to share your strategy code with me ?
 
Last edited:
It’s probably better to separate the indicator and backtesting tool to test these. There is strategy type in ToS that handles order management for backtesting. We would be replicating that in the indicator but almost there anyway. All can be done, but will take time.why on 444
Why on friday around noon, there was a warning but not a buy confirmation? what filter kept us out?

 
@babouin77 If you look at the candles, the TS_MACD_BB line, and the moving averages, you will notice that they are showing lackluster momentum... There is little gap between the first positive dot of the TS_MACD_BB and it didn't improve by the second dot, followed by a decline... The same goes for the candles themselves, and the angle of the moving averages... Just not enough momentum and it died off rapidly, pulled back, and then never took off... Nobody wants to enter an languishing scalping trade... We want it to take off, make us some profits, and allow us to exit before momentum diminishes... That momentum just wasn't there...
 
Status
Not open for further replies.

New Indicator: Buy the Dip

Check out our Buy the Dip indicator and see how it can help you find profitable swing trading ideas. Scanner, watchlist columns, and add-ons are included.

Download the indicator

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