Remove stocks with existing buy signals from Explorations

I'm using a strategy that buys breakouts with stop orders and then trails the breakout (red line). I do a nightly review to find stocks and know where to place my stops for the next day with an Exploration. The little bar at the bottom turns Green when all the filter criteria are met and this stock shown would show up in the Exploration.

The way my strategy is coded, it won't buy subsequent breakouts until the first is exited though, so stocks like this one show up in the Exploration (meets the rest of the Filter criteria) despite the strategy not taking buys on this one. Is there a way to check if there is an active Buy order for a stock to remove it from the Exploration results if so?

buy signals

@millerrh, you provide good detail of your goal but you haven't posted your code...

You could use 'Buy', 'Sell', 'inTrade' and 'activeBuyOrder' variables to break-up your conditions.

Then in the Explorer just use Filter = Buy AND NOT activeBuyOrder to only show new first signal buys.

Hi @TrendSurfer, you have the right idea of what I'm after. My code is rather lengthy and most of it not relevant to the question so was reluctant to paste it in.

I was mostly curious if there was some built-in variable that can check for this status of being inTrade or not. Looks like maybe not and I'd need to code it in, so I'll work on a simpler example that illustrates the question better and post some code to review.

Thanks!

'inTrade' is a custom variable, eg.

inTrade = Flip(Buy, Sell);

Hi @TrendSurfer, here is the code to this strategy cleaned up a bit with explanations. You can see how I have my Exploration Filter code as part of the strategy so I use this strategy as an Exploration for nightly screens.

The ticker I posted the screenshot of above is FUTU. So (at this time) this is one stock that is showing up in my Exploration screen that I'd like to remove since it already has a buy triggered on it and the backtester would not take a new buy. Therefore, I'd like to remove it from my scans and add some sort of inTrade variable to the Filter list.

Another question popped up as I was preparing this code. Is the following setting of False correct?

SetOption("ActivateStopsImmediately", False); // Stop behavior defined by trailing stop below - IS THIS THE CORRECT SETTING?

I have a trailing stop defined in my code and the strategy will exit the same day using the trailing stop (on red candles). I switched this to True and it completely broke the performance of this strategy (likely due to the tight stops triggering when they shouldn't, which is why I have it set to False). But wanted to confirm that logic.

Code below:

/*
SIMPLE DC CHECK IF IN POSITION
This strategy looks for pullbacks in uptrends (i.e. Flags) anticipating that they will break bullish and continue the trend.
Simplified and added explanation to the code to post to Amibroker Forum for assistance in adding a Filter so that stocks
that already have a buy signal won't show up.
*/

#include_once "Formulas\Norgate Data\Norgate Data Functions.afl"

// ==========================================================================================
// === TRADING SYSTEM PARAMETERS ===
// ==========================================================================================
SetOption("InitialEquity", 100000);
SetTradeDelays( 0, 0, 0, 0 ); // Trades intra-day with stop orders that are placed the night before
SetOption("AllowPositionShrinking", True);
RoundLotSize = 1;  // Disallow fractional share purchasing
SetOption("MaxOpenPositions", 12); // Maximum number of open positions: 30
SetOption("AccountMargin", 50); // 100 = Cash account, 75 = Using half available margin, 50 = 2X margin


// ==========================================================================================
// === RISK MANAGEMENT & POSITION SIZING ===
// ==========================================================================================
// === INITIAL (MAX) STOP LOSS ====	
SetOption("ActivateStopsImmediately", False); // Stop behavior defined by trailing stop below - IS THIS THE CORRECT SETTING?
stopLoss = 4;
ApplyStop(stopTypeLoss, stopModePercent, stopLoss, ExitAtStop = 1, True);  // Allows for intraday stops even with TradeDelays

// === POSITION SIZING ===
PositionRisk = 1.0; // Percentage of account at risk if wrong
PosSize = 100 * PositionRisk / stopLoss; // Position size as a percent of equity for a given stop level
SetPositionSize(PosSize, spsPercentOfEquity);


// ==========================================================================================
// === PLOT CHART & INDICATORS ===
// ==========================================================================================
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

// Donchain Channels
pdsU=4;  // High channel lookback
pdsL=5;  // Low channel lookback

DonchianUpper =HHV(H,pdsU);
DonchianLower = LLV(L,pdsL);

Plot(DonchianUpper,"DU",color = 2,styleDashed);
Plot(DonchianLower,"DL",color = 2, styleDashed);

// Moving Averages (use Nz to avoid lack of history screening strong stocks out)
sma50 = Nz(ma(Close, 50));
sma150 = Nz(ma(Close, 150));

Plot(sma50,"50MA",color = 3, styleNoTitle);
Plot(sma150,"150MA",color = colorWhite, styleNoTitle);


// ==========================================================================================
// === FLAG DETECTION === https://forum.amibroker.com/t/high-tight-flag-power-play-detection/21895
// ==========================================================================================
flagLookback = 13; // Number of bars to look back for top of flag
PoleHigh = HHV(H, flagLookback);  // Highest high within the lookback period
PHBar 	 = HHVBars(H, flagLookback);  // How many bars back the pivot high bar occurred
	
FlagLow = LLV(L, PHBar);  // Flag Low is the lowest price since PoleHigh
FLBar = LLVBars(L, PHBar);  // How many bars back is the low point of the flag

flagPoleLookback = 21;  // Look ~20 days prior to the pole for shorter term flags
PoleLow = Ref(LLV(L, flagPoleLookback), -PHBar-1);  
PLBar = Ref(LLVBars(L, flagPoleLookback), -PHBar-1);

// Flag characteristics
PoleLength = Nz((PoleHigh - PoleLow)/PoleLow);  // Percentage move that forms the flag pole
FlagDepth = Nz((PoleHigh - FlagLow)/PoleHigh);  // Percentage retracement off the highs
FlagRatio = Nz(FlagDepth/PoleLength);  // Flag-to-Pole ratio

// Flag Requirements
Flag = 
  PoleLength > 0.10 AND  // Must have had at least a 10% rise
  FlagDepth < 0.25 AND // Flag must not have come down more than 25% off the flag pole top
  FlagRatio < 0.5 AND  // Flag cannot have retraced more than 50% of the initial move
  PHBar > 1;  // Flag must be more than two candles (will trigger at third)

PlotShapes(Flag*shapeCircle, colorBlue, 0, Low);// Plot dots indicating consolidation meets requirements


// ==========================================================================================
// === FILTERING AND SCREENING CRITERIA ===
// ==========================================================================================
// Set other non-chart visible variables
adr = MA((High - Low) / abs(Low) * 100, 21);
vol = MA(Volume, 20); 

Filter = 
  DonchianUpper > sma50 AND  // when the buy is triggered stock is above the 50 SMA
  Close > sma150 AND  // Only look at stocks in Stage 2 uptrends as defined by the 30 week/150 day MA (Stain Weinstein)
  Flag == True AND  // The screen the night before should show the stock being in a proper consolidation
  adr >= 4.0 AND  // Look for stocks with higher average daily ranges
  vol >= 300000 AND  // Filter out illiquid stocks
  Close >= 1.5;  // Filter out penny stocks
  
  
// Filter Ribbon - add for better visibility when the strategy thinks a security is viable/not viable
Color = IIf(Filter,0,1);
Plot ( 1, "", Color, styleArea |styleNoLabel | styleOwnScale , 0, 100);
  
// ==========================================================================================
// === BUY & SELL LOGIC ===
// ==========================================================================================
// === NORGATE VARIABLES TO AVOID DESLISTED STOCKS ===
dt = DateTime();
bi = BarIndex();
delistedSecurity = Nz(DateTimeDiff(dt, GetFnData("DelistingDate")) >= 0);
barsBeforeDelisting = LastValue(ValueWhen(dt == GetFnData("DelistingDate"), bi, 1)) -bi;
OnSecondLastBarOfDelistedSecurity = barsBeforeDelisting == 1;
OnLastTwoBarsOfDelistedSecurity = barsBeforeDelisting == 2 OR barsBeforeDelisting == 1 OR delistedSecurity;

// === BUY AND SELL LOGIC
Buy = (High > Ref(DonchianUpper, -1)) AND Ref(Filter, -1)
  AND NOT OnLastTwoBarsOfDelistedSecurity;
  //AND (NorgateIndexConstituentTimeSeries("$SPX") OR NorgateIndexConstituentTimeSeries("$NDX"));  // Unhide to for historical testing


BuyPrice=Max(Ref(DonchianUpper, -1), Open);

// == TRAILING STOP ===
// Initialize variables
Sell=0;
trailArray = Null;
trailStop = 0;

//Trailing stop logic
for( i = 0; i < BarCount; i++ )
{  
  if( trailstop == 0 AND Buy[ i ] ) 
  { 
	trailstop = BuyPrice[i] * (1- stopLoss[i]/100);  // Use stoploss level
  }
  else Buy[i] = 0; // remove excess buy signals
  if( trailstop > 0 AND Low[ i ] < trailstop AND (Buy[i] != True OR (Buy[i] == True AND Close[i] < Open[i])))  // adding Buy check ensures you don't stop out on the breakout candle when the stop is within it unless it's a bearish candle
   {   
	 Sell[ i ] = 1; 
	 SellPrice[ i ] = Min( Open[ i ], trailstop );
	 trailstop = 0;
   }
   
  if( trailstop > 0 )
   {
	  trailStop = Max(DonchianLower[i], trailStop); 
	  trailARRAY[ i ] = trailstop;
   }
}


Plot(trailArray, "Trailing Stop Level", colorRed, styleThick);

// Overwrite sells to ensure not holding deslisted securities
Sell = Sell OR OnSecondLastBarOfDelistedSecurity;

// Plot arrows indicating trades
PlotShapes(IIf(Buy, shapeUpTriangle, shapeNone),color = colorLime, 0, L, Offset=-50);
PlotShapes(IIf(Sell, shapeDownTriangle, shapeNone),color = colorRed, 0, H, Offset=-50);


// ==========================================================================================
// === POSITION SCORE FOR RANKING STOCKS ===
// ==========================================================================================
PositionScore = Ref(vol, -1); // sort by most liquid stocks


// ==========================================================================================
// === EXPLORATION / SCANNING COLUMNS ===
// ==========================================================================================
AddTextColumn(FullName(), "Name");
AddTextColumn( SectorID(1), "Sector");
AddTextColumn(IndustryID(1), "Industry Name");
AddColumn(adr, "ADR", 1.1);
AddColumn(vol, "Avg. Volume", 1.0);

// Add other things to title bar I want to see
Title += StrFormat(" | ADR: %.1f", ADR);  // Add ADR to the title of charts

I think I answered my own question about

SetOption("ActivateStopsImmediately", False); // Stop behavior defined by trailing stop below - IS THIS THE CORRECT SETTING?

When set to true, a big bullish breakout candle can trigger the stoploss, despite it being the exact breakout I'm anticipating. See NVDA on 12/8/22 as an example.

So setting to False seems to fix this and gives me the expected no stop out in this location.

breakout

Yes, because if you are entering on a buy stop limit order then AmiBroker doesn't know what happened first on that bar - your stop loss level was hit after your trade was opened or your stop loss level was hit before your trade was opened and never got hit after your trade was opened.

1 Like

Control that in your existing for loop or with the 'Flip' function after your for loop.

Also,

Buy[i] != True

Can be written as

NOT Buy[i]

And

Buy[i] == True

Can be written simply as

Buy[i]

And don't use assignments on assignments

Plot(sma50,"50MA",color = 3, styleNoTitle); // Not proper way, misuse of memory

Should be written as

Plot(sma50,"50MA", 3, styleNoTitle);

or like this

Plot(sma50,"50MA", /*color*/ 3, styleNoTitle);

Hi @TrendSurfer, thanks for your extra coding tips in your response! I was able to successfully create a new variable that toggles between 0 and 1 depending on if the stock has an open buy signal or not within my for loop. I added a column in the exploration that shows this and it works. But for some reason, the Filter checking for this is not filtering away the 1's and I'm not sure why.

/*
SIMPLE DC CHECK IF IN POSITION
This strategy looks for pullbacks in uptrends (i.e. Flags) anticipating that they will break bullish and continue the trend.
Simplified and added explanation to the code to post to Amibroker Forum for assistance in adding a Filter so that stocks
that already have a buy signal won't show up.
*/

#include_once "Formulas\Norgate Data\Norgate Data Functions.afl"

// ==========================================================================================
// === TRADING SYSTEM PARAMETERS ===
// ==========================================================================================
SetOption("InitialEquity", 100000);
SetTradeDelays( 0, 0, 0, 0 ); // Trades intra-day with stop orders that are placed the night before
SetOption("AllowPositionShrinking", True);
RoundLotSize = 1;  // Disallow fractional share purchasing
SetOption("MaxOpenPositions", 12); // Maximum number of open positions: 30
SetOption("AccountMargin", 50); // 100 = Cash account, 75 = Using half available margin, 50 = 2X margin


// ==========================================================================================
// === RISK MANAGEMENT & POSITION SIZING ===
// ==========================================================================================
// === INITIAL (MAX) STOP LOSS ====	
SetOption("ActivateStopsImmediately", False); // Stop behavior defined by trailing stop below - IS THIS THE CORRECT SETTING?
stopLoss = 4;
ApplyStop(stopTypeLoss, stopModePercent, stopLoss, ExitAtStop = 1, True);  // Allows for intraday stops even with TradeDelays

// === POSITION SIZING ===
PositionRisk = 1.0; // Percentage of account at risk if wrong
PosSize = 100 * PositionRisk / stopLoss; // Position size as a percent of equity for a given stop level
SetPositionSize(PosSize, spsPercentOfEquity);


// ==========================================================================================
// === PLOT CHART & INDICATORS ===
// ==========================================================================================
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

// Donchain Channels
pdsU=4;  // High channel lookback
pdsL=5;  // Low channel lookback

DonchianUpper =HHV(H,pdsU);
DonchianLower = LLV(L,pdsL);

Plot(DonchianUpper,"DU",/*color*/ 2,styleDashed);
Plot(DonchianLower,"DL",/*color*/ 2, styleDashed);

// Moving Averages (use Nz to avoid lack of history screening strong stocks out)
sma50 = Nz(ma(Close, 50));
sma150 = Nz(ma(Close, 150));

Plot(sma50,"50MA",/*color*/ 3, styleNoTitle);
Plot(sma150,"150MA",colorWhite, styleNoTitle);


// ==========================================================================================
// === FLAG DETECTION === https://forum.amibroker.com/t/high-tight-flag-power-play-detection/21895
// ==========================================================================================
flagLookback = 13; // Number of bars to look back for top of flag
PoleHigh = HHV(H, flagLookback);  // Highest high within the lookback period
PHBar 	 = HHVBars(H, flagLookback);  // How many bars back the pivot high bar occurred
	
FlagLow = LLV(L, PHBar);  // Flag Low is the lowest price since PoleHigh
FLBar = LLVBars(L, PHBar);  // How many bars back is the low point of the flag

flagPoleLookback = 21;  // Look ~20 days prior to the pole for shorter term flags
PoleLow = Ref(LLV(L, flagPoleLookback), -PHBar-1);  
PLBar = Ref(LLVBars(L, flagPoleLookback), -PHBar-1);

// Flag characteristics
PoleLength = Nz((PoleHigh - PoleLow)/PoleLow);  // Percentage move that forms the flag pole
FlagDepth = Nz((PoleHigh - FlagLow)/PoleHigh);  // Percentage retracement off the highs
FlagRatio = Nz(FlagDepth/PoleLength);  // Flag-to-Pole ratio

// Flag Requirements
Flag = 
  PoleLength > 0.10 AND  // Must have had at least a 10% rise
  FlagDepth < 0.25 AND // Flag must not have come down more than 25% off the flag pole top
  FlagRatio < 0.5 AND  // Flag cannot have retraced more than 50% of the initial move
  PHBar > 1;  // Flag must be more than two candles (will trigger at third)

PlotShapes(Flag*shapeCircle, colorBlue, 0, Low);// Plot dots indicating consolidation meets requirements


// ==========================================================================================
// === FILTERING AND SCREENING CRITERIA ===
// ==========================================================================================
// Set other non-chart visible variables
adr = MA((High - Low) / abs(Low) * 100, 21);
vol = MA(Volume, 20); 
inTrade = 0;

Filter = 
  DonchianUpper > sma50 AND  // when the buy is triggered stock is above the 50 SMA
  Close > sma150 AND  // Only look at stocks in Stage 2 uptrends as defined by the 30 week/150 day MA (Stain Weinstein)
  Flag == True AND  // The screen the night before should show the stock being in a proper consolidation
  adr >= 4.0 AND  // Look for stocks with higher average daily ranges
  vol >= 300000 AND  // Filter out illiquid stocks
  inTrade == 0 AND // Filter out stocks that don't have current buy signals
  Close >= 1.5;  // Filter out penny stocks
  
  
// Filter Ribbon - add for better visibility when the strategy thinks a security is viable/not viable
Color = IIf(Filter,0,1);
Plot ( 1, "", Color, styleArea |styleNoLabel | styleOwnScale , 0, 100);
  
// ==========================================================================================
// === BUY & SELL LOGIC ===
// ==========================================================================================
// === NORGATE VARIABLES TO AVOID DESLISTED STOCKS ===
dt = DateTime();
bi = BarIndex();
delistedSecurity = Nz(DateTimeDiff(dt, GetFnData("DelistingDate")) >= 0);
barsBeforeDelisting = LastValue(ValueWhen(dt == GetFnData("DelistingDate"), bi, 1)) -bi;
OnSecondLastBarOfDelistedSecurity = barsBeforeDelisting == 1;
OnLastTwoBarsOfDelistedSecurity = barsBeforeDelisting == 2 OR barsBeforeDelisting == 1 OR delistedSecurity;

// === BUY AND SELL LOGIC
Buy = (High > Ref(DonchianUpper, -1)) AND Ref(Filter, -1)
  AND NOT OnLastTwoBarsOfDelistedSecurity;
  //AND (NorgateIndexConstituentTimeSeries("$SPX") OR NorgateIndexConstituentTimeSeries("$NDX"));  // Unhide to for historical testing


BuyPrice=Max(Ref(DonchianUpper, -1), Open);

// == TRAILING STOP ===
// Initialize variables
Sell=0;
trailArray = Null;
trailStop = 0;

//Trailing stop logic
for( i = 0; i < BarCount; i++ )
{  
  if( trailstop == 0 AND Buy[ i ] ) 
  { 
	trailstop = BuyPrice[i] * (1- stopLoss[i]/100);  // Use stoploss level
	inTrade = 1;
  }
  else Buy[i] = 0; // remove excess buy signals
  if( trailstop > 0 AND Low[ i ] < trailstop AND (NOT Buy[i] OR (Buy[i] AND Close[i] < Open[i])))  // adding Buy check ensures you don't stop out on the breakout candle when the stop is within it unless it's a bearish candle
   {   
	 Sell[ i ] = 1; 
	 SellPrice[ i ] = Min( Open[ i ], trailstop );
	 trailstop = 0;
	 inTrade = 0;
   }
   
  if( trailstop > 0 )
   {
	  trailStop = Max(DonchianLower[i], trailStop); 
	  trailARRAY[ i ] = trailstop;
   }
}


Plot(trailArray, "Trailing Stop Level", colorRed, styleThick);

// Overwrite sells to ensure not holding deslisted securities
Sell = Sell OR OnSecondLastBarOfDelistedSecurity;

// Plot arrows indicating trades
PlotShapes(IIf(Buy, shapeUpTriangle, shapeNone),colorLime, 0, L, Offset=-50);
PlotShapes(IIf(Sell, shapeDownTriangle, shapeNone),colorRed, 0, H, Offset=-50);


// ==========================================================================================
// === POSITION SCORE FOR RANKING STOCKS ===
// ==========================================================================================
PositionScore = Ref(vol, -1); // sort by most liquid stocks


// ==========================================================================================
// === EXPLORATION / SCANNING COLUMNS ===
// ==========================================================================================
AddTextColumn(FullName(), "Name");
AddTextColumn( SectorID(1), "Sector");
AddTextColumn(IndustryID(1), "Industry Name");
AddColumn(adr, "ADR", 1.1);
AddColumn(vol, "Avg. Volume", 1.0);
AddColumn(inTrade, "In Trade?", 1.0);

// Add other things to title bar I want to see
Title += StrFormat(" | ADR: %.1f", ADR);  // Add ADR to the title of charts

Because your 'inTrade' variable is a static zero value when you are assigning your 'Filter' variable.

Your 'inTrade' variable is not dynamic until after the fact.

1 Like

I think I got it. I renamed my original Filter variable I use for screening for trades as tradeFilter and then after the for loop that dictates my trades, I introduced the Exploration Filter variable as follows:

Filter = tradeFilter AND NOT inTrade;

Updated code:

/*
SIMPLE DC CHECK IF IN POSITION
This strategy looks for pullbacks in uptrends (i.e. Flags) anticipating that they will break bullish and continue the trend.
Simplified and added explanation to the code to post to Amibroker Forum for assistance in adding a Filter so that stocks
that already have a buy signal won't show up.
*/

#include_once "Formulas\Norgate Data\Norgate Data Functions.afl"

// ==========================================================================================
// === TRADING SYSTEM PARAMETERS ===
// ==========================================================================================
SetOption("InitialEquity", 100000);
SetTradeDelays( 0, 0, 0, 0 ); // Trades intra-day with stop orders that are placed the night before
SetOption("AllowPositionShrinking", True);
RoundLotSize = 1;  // Disallow fractional share purchasing
SetOption("MaxOpenPositions", 12); // Maximum number of open positions: 30
SetOption("AccountMargin", 50); // 100 = Cash account, 75 = Using half available margin, 50 = 2X margin


// ==========================================================================================
// === RISK MANAGEMENT & POSITION SIZING ===
// ==========================================================================================
// === INITIAL (MAX) STOP LOSS ====	
SetOption("ActivateStopsImmediately", False); // Stop behavior defined by trailing stop below - IS THIS THE CORRECT SETTING?
stopLoss = 4;
ApplyStop(stopTypeLoss, stopModePercent, stopLoss, ExitAtStop = 1, True);  // Allows for intraday stops even with TradeDelays

// === POSITION SIZING ===
PositionRisk = 1.0; // Percentage of account at risk if wrong
PosSize = 100 * PositionRisk / stopLoss; // Position size as a percent of equity for a given stop level
SetPositionSize(PosSize, spsPercentOfEquity);


// ==========================================================================================
// === PLOT CHART & INDICATORS ===
// ==========================================================================================
// Chart
SetChartOptions(0,chartShowArrows|chartShowDates);
_N(Title = StrFormat("{{NAME}} - " + FullName() + " | {{INTERVAL}} {{DATE}}: Open %g, Hi %g, Lo %g, Close %g (%.1f%%) {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 ) ) ));
Plot( C, "Close", ParamColor("Color", colorDefault ), styleNoTitle | ParamStyle("Style") | GetPriceStyle() ); 

// Donchain Channels
pdsU=4;  // High channel lookback
pdsL=5;  // Low channel lookback

DonchianUpper =HHV(H,pdsU);
DonchianLower = LLV(L,pdsL);

Plot(DonchianUpper,"DU",/*color*/ 2,styleDashed);
Plot(DonchianLower,"DL",/*color*/ 2, styleDashed);

// Moving Averages (use Nz to avoid lack of history screening strong stocks out)
sma50 = Nz(ma(Close, 50));
sma150 = Nz(ma(Close, 150));

Plot(sma50,"50MA",/*color*/ 3, styleNoTitle);
Plot(sma150,"150MA",colorWhite, styleNoTitle);


// ==========================================================================================
// === FLAG DETECTION === https://forum.amibroker.com/t/high-tight-flag-power-play-detection/21895
// ==========================================================================================
flagLookback = 13; // Number of bars to look back for top of flag
PoleHigh = HHV(H, flagLookback);  // Highest high within the lookback period
PHBar 	 = HHVBars(H, flagLookback);  // How many bars back the pivot high bar occurred
	
FlagLow = LLV(L, PHBar);  // Flag Low is the lowest price since PoleHigh
FLBar = LLVBars(L, PHBar);  // How many bars back is the low point of the flag

flagPoleLookback = 21;  // Look ~20 days prior to the pole for shorter term flags
PoleLow = Ref(LLV(L, flagPoleLookback), -PHBar-1);  
PLBar = Ref(LLVBars(L, flagPoleLookback), -PHBar-1);

// Flag characteristics
PoleLength = Nz((PoleHigh - PoleLow)/PoleLow);  // Percentage move that forms the flag pole
FlagDepth = Nz((PoleHigh - FlagLow)/PoleHigh);  // Percentage retracement off the highs
FlagRatio = Nz(FlagDepth/PoleLength);  // Flag-to-Pole ratio

// Flag Requirements
Flag = 
  PoleLength > 0.10 AND  // Must have had at least a 10% rise
  FlagDepth < 0.25 AND // Flag must not have come down more than 25% off the flag pole top
  FlagRatio < 0.5 AND  // Flag cannot have retraced more than 50% of the initial move
  PHBar > 1;  // Flag must be more than two candles (will trigger at third)

PlotShapes(Flag*shapeCircle, colorBlue, 0, Low);// Plot dots indicating consolidation meets requirements


// ==========================================================================================
// === FILTERING AND SCREENING CRITERIA ===
// ==========================================================================================
// Set other non-chart visible variables
adr = MA((High - Low) / abs(Low) * 100, 21);
vol = MA(Volume, 20); 
inTrade = 0;

tradeFilter = 
  DonchianUpper > sma50 AND  // when the buy is triggered stock is above the 50 SMA
  Close > sma150 AND  // Only look at stocks in Stage 2 uptrends as defined by the 30 week/150 day MA (Stain Weinstein)
  Flag == True AND  // The screen the night before should show the stock being in a proper consolidation
  adr >= 4.0 AND  // Look for stocks with higher average daily ranges
  vol >= 300000 AND  // Filter out illiquid stocks
  Close >= 1.5;  // Filter out penny stocks
  
  
// Filter Ribbon - add for better visibility when the strategy thinks a security is viable/not viable
Color = IIf(tradeFilter,0,1);
Plot ( 1, "", Color, styleArea |styleNoLabel | styleOwnScale , 0, 100);
  
// ==========================================================================================
// === BUY & SELL LOGIC ===
// ==========================================================================================
// === NORGATE VARIABLES TO AVOID DESLISTED STOCKS ===
dt = DateTime();
bi = BarIndex();
delistedSecurity = Nz(DateTimeDiff(dt, GetFnData("DelistingDate")) >= 0);
barsBeforeDelisting = LastValue(ValueWhen(dt == GetFnData("DelistingDate"), bi, 1)) -bi;
OnSecondLastBarOfDelistedSecurity = barsBeforeDelisting == 1;
OnLastTwoBarsOfDelistedSecurity = barsBeforeDelisting == 2 OR barsBeforeDelisting == 1 OR delistedSecurity;

// === BUY AND SELL LOGIC
Buy = (High > Ref(DonchianUpper, -1)) AND Ref(tradeFilter, -1)
  AND NOT OnLastTwoBarsOfDelistedSecurity;
  //AND (NorgateIndexConstituentTimeSeries("$SPX") OR NorgateIndexConstituentTimeSeries("$NDX"));  // Unhide to for historical testing


BuyPrice=Max(Ref(DonchianUpper, -1), Open);

// == TRAILING STOP ===
// Initialize variables
Sell=0;
trailArray = Null;
trailStop = 0;
inTrade = 0;

//Trailing stop logic
for( i = 0; i < BarCount; i++ )
{  
  if( trailstop == 0 AND Buy[ i ] ) 
  { 
	trailstop = BuyPrice[i] * (1- stopLoss[i]/100);  // Use stoploss level
	inTrade = 1;
  }
  else Buy[i] = 0; // remove excess buy signals
  if( trailstop > 0 AND Low[ i ] < trailstop AND (NOT Buy[i] OR (Buy[i] AND Close[i] < Open[i])))  // adding Buy check ensures you don't stop out on the breakout candle when the stop is within it unless it's a bearish candle
   {   
	 Sell[ i ] = 1; 
	 SellPrice[ i ] = Min( Open[ i ], trailstop );
	 trailstop = 0;
	 inTrade = 0;
   }
   
  if( trailstop > 0 )
   {
	  trailStop = Max(DonchianLower[i], trailStop); 
	  trailARRAY[ i ] = trailstop;
   }
}


Plot(trailArray, "Trailing Stop Level", colorRed, styleThick);

// Overwrite sells to ensure not holding deslisted securities
Sell = Sell OR OnSecondLastBarOfDelistedSecurity;

// Plot arrows indicating trades
PlotShapes(IIf(Buy, shapeUpTriangle, shapeNone),colorLime, 0, L, Offset=-50);
PlotShapes(IIf(Sell, shapeDownTriangle, shapeNone),colorRed, 0, H, Offset=-50);


// ==========================================================================================
// === POSITION SCORE FOR RANKING STOCKS ===
// ==========================================================================================
PositionScore = Ref(vol, -1); // sort by most liquid stocks


// ==========================================================================================
// === EXPLORATION / SCANNING COLUMNS ===
// ==========================================================================================

Filter = tradeFilter AND NOT inTrade; // Filter out stocks that don't have current buy signals

AddTextColumn(FullName(), "Name");
AddTextColumn( SectorID(1), "Sector");
AddTextColumn(IndustryID(1), "Industry Name");
AddColumn(adr, "ADR", 1.1);
AddColumn(vol, "Avg. Volume", 1.0);
AddColumn(inTrade, "In Trade?", 1.0);

// Add other things to title bar I want to see
Title += StrFormat(" | ADR: %.1f", ADR);  // Add ADR to the title of charts

1 Like

This topic was automatically closed 100 days after the last reply. New replies are no longer allowed.