S&C Magazine Jan 2018 Traders Tips

How to plot MACD and ADX in this chart ?

Larry, thanks a lot for your input! :+1:

I've noticed one small problem. You use Param() functions conditionally, which causes some problems when switching chart types. New chart type's parameters are not accessible right after the change and after reopening Parameters window, they are mixed with the previous ones. Resetting causes switching back to the first chart type. I think that Param() functions shouldn't be used conditionally. Their values are cached and are not re-read during subsequent formula evaluations. Take a look:

SC Magazine

Regards :slight_smile:


Thanks a lot - I haven´t seen before!


nice job! Thanks for sharing.

I too worked on this TASC article. I went a little further than you since in addition to the indicator (basically same code) I’m also including an exploration and a very basic trading system based on the rules that were explained in the article by Barbara Starr associated to January 2018 Trader’s Tips section.

I made an attempt to write a full-fledged .afl.
This is something I’m still not that comfortable since I usually write code snippets only for myself; I hope the result will be clear enough.
Feel free to modify it as per your preferences and, as always, all suggestions to improve it/fix bugs are welcome!

At the end of the code, I also added some suggested usage for the trading system.
Actually, I did not spend a lot of time to backtest it, but I saw that this system seems to work well (getting better results than B&H in the same period) when the market uptrend is well defined (it is a long only system) and the instruments selection is the right one (does this not apply to all systems?)

Probably one needs to find some good rules to filter and rank the used instruments to get more significative outperformance.
Up to you to find the solution (and if you get it, please, share it with us!)

The user may easily plot the other indicators (MACD, ADX) in separate panes (something one can do using your or similar code).
The trading systems rules use also the CCI.
I decided to (optionally) visually “include” it the main chart using on the background some dark colors and a staircase dashed line: the CCI indicator, in this case, is relevant only in a binary mode (over or below 0).

Here is the code (requires version 6.20)

// "The CAM Indicator For Trends And Countertrends"
// Based on TASC - Traders' Tip - January 2018
// The author of this code makes no claims of originality regarding the combined 
// use of certain indicators and for the suggested trading system, that was 
// described in an article titled "The CAM Indicator For Trends And Countertrends" 
// by Barbara Starr Phd., published in the January 2018 issue of the 
// "Technical Analysis of  STOCKS & COMMODITIES The Traders’ Magazine"
// ("CAM" stands for Coordinated ADX and MACD indicator)
// Code ported to AmiBroker by G. Bonariva from other trading systems code 
// samples and notes, posted here:
// http://traders.com/Documentation/FEEDbk_docs/2018/01/TradersTips.html
// DISCLAIMER: This AmiBroker formula is provided "as is". 

/* Requirements: -------------------------------------------------------------*/
Version(6.20); // Needed for AddMultiTextColumn

/* Constants -----------------------------------------------------------------*/

// These are set per default as recommended by the TASC's article author 
// Parametrize/Change these values and/or ranges as per your own criteria
adxPeriod = 10;                      // Param("ADX period", 10, 5, 25, 1);
macdFastPeriod = 12;                 // Param("MACD Fast period", 12, 6, 24, 2); 
macdSlowPeriod = 26;                 // Param("MACD Slow period", 26, 14, 32, 2);
emaPeriod = 13;                      // Param("EMA period", 13, 8, 21, 1);
cciPeriod = 14;                      // Param( "CCI period", 14, 10, 30, 1 );

camUPColor = colorBrightGreen;       // ParamColor("UP color", colorGreen);
camDNColor = colorRed;				 // ParamColor("DN color", colorRed); 	
camPBColor = colorGold;              // ParamColor("PB color", colorGold); 
camCTColor = ColorRGB(63, 63, 255);  // ParamColor("CT color", colorBlue);  

// Trading system
initialEquity = 100000;
maxOpenPositions = 20;
scoreLookBackPeriod = 14; 
commissionMode = 2;    // 0: portfolio manager commission table 
					   // 1: percent of trade 
					   // 2: $ per trade
					   // 3: $ per share/contract 
commissionAmount = 5;  // Here amount per trade 
RoundLotSize = 1;      // No fractional shares 

/* Options -------------------------------------------------------------------*/

// These are NOT specified in the article.
// The backtest settings that are not specified in code will use the UI ones

// Set Commission
SetOption( "InitialEquity", initialEquity );
SetOption("MaxOpenPositions", maxOpenPositions);
SetOption("CommissionMode", commissionMode);         
SetOption("CommissionAmount", commissionAmount);     
SetOption( "AllowSameBarExit", False );
SetOption( "AllowPositionShrinking", False );
SetPositionSize( 100 / maxOpenPositions, spsPercentOfEquity ); // Fixed Fractional Sizing

/* Variables and parameters: -------------------------------------------------*/

// Optional - Use colors in background based on CCI > 0 (default dark green/red)
bkgCciGtz = ParamToggle("Show CCI > 0 with colors in background", "No|Yes", 1);
bkgColorCciGtz = ParamColor("Background color when CCI > 0", ColorRGB(0, 39, 0));
bkgColorCciLtz = ParamColor("Background color when CCI <= 0", ColorRGB(39, 0, 0));

showArrows = ParamToggle("Show Buy/Sell arrows", "No|Yes", 1);
buyArrowColor = ParamColor("Buy Arrow color", colorWhite);
sellArrowColor = ParamColor("Sell Arrow color", colorWhite);

/* Functions/Procedures : ----------------------------------------------------*/

// Returns a pale green color when the array values is > 0 else a pale red one
function cgr(a) {
  return iif(a > 0, ColorRGB(233, 255, 233), ColorRGB(255, 233, 233));

/* Calculations/Rules: -------------------------------------------------------*/

macdArray = MACD( macdFastPeriod, macdSlowPeriod ) ;
adxArray = ADX( adxPeriod );
cciArray = CCI( cciPeriod );
emaArray = EMA(C, emaPeriod);

macdRising = macdArray > Ref( macdArray, -1 );
adxRising = adxArray > Ref( adxArray, -1 );
cciPositive = cciArray > 0;
cAboveEqEma = C >= emaArray;  
cCrossingEma = Cross(C, emaArray);

camUP = ((adxRising == True ) AND (macdRising == True ));  // Uptrend
camPB = ((adxRising == False) AND (macdRising == False));  // Pullback
camDN = ((adxRising == True ) AND (macdRising == False));  // Downtrend
camCT = ((adxRising == False) AND (macdRising == True ));  // CounterTend

// a bit verbose to better understand it
plotColor = iif(camUP, camUPColor,
				iif(camPB, camPBColor,
					iif(camDN, camDNColor,
                        IIf(camCT, camCTColor, colorDefault))));

// same logic as above
plotLabelIdx = 	iif(camUP, 1, iif(camPB, 2, iif(camDN, 3, IIf(camCT, 4, 0 ) ) ) );

enterLongRule = ((plotColor == camPBColor) AND (cciArray > 0)) OR
				((plotColor == camCTColor) AND (cCrossingEma)); 

exitLongRule = (plotColor == camDNColor) AND (C < emaArray);

/* Exploration: --------------------------------------------------------------*/

Filter = enterLongRule OR exitLongRule;
// Filter = 1; // Uncomment if you prefer to see all the values
AddColumn(C, "Close");
// The background color correspond to the condition in the [] brackets in the headers
AddColumn(adxArray, "ADX [rising]", 1.2, colorDefault, cgr(adxRising));
AddColumn(macdArray, "MACD [rising]", 1.2, colorDefault, cgr(macdRising));
// Added spaces for presentation 
// Would be nice to have an optional Text Alignment param (L,C,R) for headers too...
AddColumn(cciArray, "CCI [> 0]", 1.2, colorDefault, cgr(cciPositive));
AddMultiTextColumn(plotLabelIdx, "\n   UP   \n   PB   \n   DN   \n   CT  \n", "  CAM", 1.2, colorBlack, plotColor, 60); 
AddMultiTextColumn(cCrossingEma, "\n  CROSSING  \n", "Cross(C, EMA)", 1.2);
AddColumn(emaArray, "[C >=] EMA", 1.2, colorDefault, cgr(CAboveEqEma));
AddMultiTextColumn(((enterLongRule * 2) + exitLongRule), "\n   EXIT   \nGO LONG \nCONFLICT\n", "Signals", 1.2);

/* Trading System (very basic) -----------------------------------------------*/

// Set options above as needed and override previous settings if optimizing

// maxOpenPos = Optimize("Max Open Positions", maxOpenPos, 5, 50, 5 );
// scoreLookBackPeriod = Optimize("LookBack period", 14, 10, 125, 1);
// PositionSize = -100/maxOpenPosition; 

// To trade only securities that trended well you need to devise your
// own pre-selection strategy. These criteria are NOT in the article...
PositionScore = 100 * RSI(scoreLookBackPeriod);
// PositionScore = (try your own formula here);

buySignal = enterLongRule;
sellSignal = exitLongRule;

BuyPrice = Open;
SellPrice = Open;	

// Buy/Sell on the next bar
Buy = Ref( buySignal, -1);
Sell = Ref( sellSignal, -1);

Buy = ExRem(Buy, Sell);
Sell = ExRem(Sell, Buy);

/* Charting/Indicator --------------------------------------------------------*/

if( Status( "Action" ) == actionIndicator) 
	SetChartBkColor( colorBlack );
	SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
	_N(Title = StrFormat("{{NAME}} - " + FullName() +
	   " - {{INTERVAL}} {{DATE}} Open %g, Hi %g, Lo %g, Close %g (%.1f%%) Vol " +
	   WriteVal( V, 1.0 ) + " {{VALUES}}", O, H, L, C, SelectedValue( ROC( C, 1 )) ));
	Plot( Close, "CAM", plotColor, styleBar|styleThick|styleNoTitle );
	Plot( emaArray, "EMA", ColorRGB(223, 223, 223), styleDashed);
	// Optional - parametrized
	if (bkgCciGtz) {
		// CCI is significant for this system only when above zero 
		Plot(cciPositive, "", ColorRGB(159, 159, 159), styleStairCase|styleDashed|styleLeftAxisScale|styleNoLabel|styleNoTitle, null, null, 0, -1);
		Plot(cciPositive, "", bkgColorCciGtz, 
			styleArea|styleLeftAxisScale|styleNoLabel|styleNoTitle, null, null, 0, -2);
		Plot(NOT cciPositive, "", bkgColorCciLtz, 
			styleArea|styleLeftAxisScale|styleNoLabel, null, null, 0, -2);
	if (showArrows) {
		PlotShapes(Buy * shapeUpArrow, buyArrowColor, 0, O, 6);
		PlotShapes(Sell * shapeDownArrow, sellArrowColor, 0, O, 6);

/* -----------------------------------------------------------------------------
Please, see the TASC Jan. 2018 article by Barbara Starr for details:

Enter LONG: Buy tomorrow at the open if today is a GOLD-colored bar 
(which represents the CAM-PB, meaning that both the 10-period ADX and 
MACD are declining) but the 14-period CCI is above zero, OR if today 
is a BLUE-colored bar (the 10-period ADX is declining but MACD is rising) 
and today’s close crosses above the 13-period EMA.||

Exit LONG: Sell tomorrow at the open if today is a RED-colored bar (which 
corresponds to the CAM-DN; that is, the 10-period ADX is rising but the 
MACD declines) and today’s close is below the 13-period EMA.

NOTE: The system works well only when the selected universe is in a positive trend. 
So filtering trades using the above rules is not be enough; to maximize the odds
of profit, it is mandatory to apply this trading system to a preselected watchlist of
names/instruments that clearly demonstrates a certain trendiness.


@beppe very nice job. Interestingly it makes money without any modifications. I liked your staircase dashed line for the CCI as I haven't seen that too commonly. I found that visually very appealing.

The common alternative is the "ribbon" approach at the bottom (see below).

And @Milosz I agree that with built in common indicators like ADX and MACD it is probably simpler to just insert them in their own pane.

For the "ribbon" i changed a couple of @beppe 's lines,

color = IIf( cciPositive, colorGreen, colorRed );
Plot( 1, "", color, styleArea|styleOwnScale,0,30,0,-1 ); // the 8th argument specifies z-order



Please, note that in my formula, unfortunately, I misspelled the article’s original author last name: the correct spelling of her name is Barbara Star (no double “r” at the end).
If you use it, please, fix it. Thanks.


Dunno abt Barbara , you,@beppe,definitey stole a star :star2: from our hearts sir.


has anyone had good results with this code.
any improvements??

how do you use this code?
i tried to run an analysis and nothing came up.
do you do it for one stock, or multiple.i tried scan and explore and no results

@colombianflag you should use it on a basket of stocks (like in the USA markets selecting them from the S&P500 or the Nasdaq100).

Please, read the notes at the end of code or, even better, try to get a copy of the magazine and study the original article to understand what kind of instruments will produce better results.

In AmiBroker you select your list of stocks to test using the "filter" settings of the analysis window.


See also this thread to learn how to combine multiple watchlists/groups/etc. to use them as your backtest/exploration "universe".

In any case, the code is just an example, and before trading it (or any other published strategy), you should do your homework finding the instruments to use, testing it well, changing it to better suit your trading style, applying your money management rules, and so on.


Dr. Star recently did a Webinar based on her article "CAM Indicator for Trends and CounterTrends" that can be found at the 27th minute of this VectorVest International Forum at https://register.gotowebinar.com/recording/6304650645144971021

Following is some info based on her 2 Stocks & Commodities articles and the aforementioned webinar:

  1. Jan 2002 article:
    a. MACD and ADX were used with standard parameters and MACD histogram was not shown
    b. Only 2 patterns discussed
    c. A 13 day simple moving avg was added for clarity

  2. Jan 2018 article:
    a. MACD was used with standard parameters with no signal line and no histogram for ease in useage
    b. ADX was modified to a 10 day period
    c. 2 new patterns added to the prior 2 and all 4 are shown with colored price bars
    d. The 13 day simple moving avg was changed to a 13 day exponential moving avg.
    e. A 14 day CCI was also added for clarity of signals

  3. VV Internation Forum Webinar
    a. MACD and ADX same as Jan 2018 article
    b. Same 4 patterns
    c. No discussion of 13 day EMA nor 14 day CCI
    d. A 50 day simple moving avg was added for clarity of signals
    e. Support and Resistance lines were added for clarity of signals
    f. Her VV long and sort searches were shown and explained using ADX(10) >20 for 1 day
    and MACD(12,26,9) > signal line over last 3 days
    g. She mentioned that outside of VV she doesn't use and numerical triggers all she needs for CAM Up is both moving up for 1 day
    h. Some discussion of intraday trading but she prefers daily signals

Note in the webinar after the questions and answer phase there is further discussion of charting and interpreting using VV charts.

Seems like a continually evolving approach to analyzing stock charts and no backtesting results or claims were made in either of the articles or the webinar.

Ed S.


Some great code sample, well done @beppe and @portfoliobuilder :

IndexDownTrend = C < MA(C,100);
liquidStock = EMA(C*V,20) > 750000;
noPennyStock = C > 1;

Applied above market/general filter to minimize drawdown, specially when overall market trend is down.

1 Like

Thanks for great work @beppe and @portfoliobuilder ,

I tried to run 30min CAM Exploration combined with TimeframeSet 2Hour Macd Histogram but looked like doesn't correspondent well with 2Hr Histogram and it created some mixed signal.

Please read attached photo1 left 30min and right 2Hr chart with True Sell signal.
Criteria filter : when 30min CAM Sell signal and 2Hour HistDownBar_Red.


Please read attached photo2 with Fasle Sell signal.
Noise : when 30min CAM Sell signal and 2Hour Histogram pullback in white color.


_SECTION_BEGIN (" Coordinated ADX and MACD ");

//moving averages
MA1 = EMA(C,20);
MA2 = EMA(C,50);

//MACD Indicator 2Hour
TimeFrameSet( 2 * inHourly) ;
Hist = (MACD()-Signal());
HistupBar_Blue = Hist > Ref (Hist,-1) ;
HistDownBar_Red = Hist < Ref (Hist,-1) ;

CAMup = ADX( 10 ) >= Ref( ADX( 10 ), -1 ) AND MACD() > Ref( MACD(), -1 ); // upward market
CAMpb = ADX( 10 ) <= Ref( ADX( 10 ), -1 ) AND MACD() < Ref( MACD(), -1 ); // pullback
CAMdn = ADX( 10 ) >= Ref( ADX( 10 ), -1 ) AND MACD() < Ref( MACD(), -1 ); // down market
CAMct = ADX( 10 ) <= Ref( ADX( 10 ), -1 ) AND MACD() > Ref( MACD(), -1 ); // counter-trend

Buy = CAMup AND Ref (CAMpb,-1) AND C > MA1 AND C > MA2 AND HistupBar_Blue OR
      CAMup AND Ref (CAMct,-1) AND C > MA1 AND C > MA2 AND HistupBar_Blue ;
Sell = CAMdn AND Ref (CAMpb,-1) AND C < MA1 AND C < MA2 AND HistDownBar_Red OR
       CAMdn AND Ref (CAMct,-1) AND C < MA1 AND C < MA2 AND HistDownBar_Red ; 

I appreciate if any one can help ...


Hi Steven,

Everything that is written in this manual, need to sink in first - Multiple Time Frame support in AFL. You are not alone! This is one of the most common query asked here in this forum. :slight_smile:

If an array is compressed (using TimeFrameSet or TimeFrameCompress) to a higher timeframe it (the array) must be expanded back. So, what are we compressing/expanding? Here are some details by Tomasz:

Here is an untested version of your code that might help:

_SECTION_BEGIN( " Coordinated ADX and MACD " );

tf = Param( "Set Higher Timeframe (in minutes)", 120, 1, 1440, 1 ) * in1Minute;

//moving averages
MA1 = EMA( C, 20 );
MA2 = EMA( C, 50 );

//MACD Indicator 2Hour
TimeFrameSet( tf ) ;
Hist = ( MACD() - Signal() );
PrevHist = Ref( Hist, -1 );

CAMup = ADX( 10 ) >= Ref( ADX( 10 ), -1 ) AND MACD() > Ref( MACD(), -1 ); // upward market
CAMpb = ADX( 10 ) <= Ref( ADX( 10 ), -1 ) AND MACD() < Ref( MACD(), -1 ); // pullback
CAMdn = ADX( 10 ) >= Ref( ADX( 10 ), -1 ) AND MACD() < Ref( MACD(), -1 ); // down market
CAMct = ADX( 10 ) <= Ref( ADX( 10 ), -1 ) AND MACD() > Ref( MACD(), -1 ); // counter-trend

expandHow = expandFirst; //expandLast;
HistupBar_Blue = TimeFrameExpand( Hist, tf, expandHow ) > TimeFrameExpand( PrevHist, tf, expandHow );
HistDownBar_Red = TimeFrameExpand( Hist, tf, expandHow ) < TimeFrameExpand( PrevHist, tf, expandHow );

Buy = CAMup AND Ref( CAMpb, -1 ) AND C > MA1 AND C > MA2 AND HistupBar_Blue OR
      CAMup AND Ref( CAMct, -1 ) AND C > MA1 AND C > MA2 AND HistupBar_Blue ;

Sell = CAMdn AND Ref( CAMpb, -1 ) AND C < MA1 AND C < MA2 AND HistDownBar_Red OR
       CAMdn AND Ref( CAMct, -1 ) AND C < MA1 AND C < MA2 AND HistDownBar_Red ;
1 Like

Hi Cougar,

I am appreciated your prompt respond and modified the code. I have run tested in 30min USDJPY all looks great but except the last 2 signal were false and against 2Hr Macd Histogram in pullback and above water level.

Would you think should add HistupBar_Blue and ( Hist across above neutral level )
HistDownBar_Red and ( Hist across below neutral level )


Looks forward to hear from you.


Honestly, I don't have an answer for that, because, its your system and you set the rules. However, quoting Tomasz for a perspective of State vs Impulse:

Also while using TimeFrameExpand() function, it is necessary to specify the mode, i.e. should you use:

  • expandLast - the compressed value is expanded starting from last bar within given period (so for example weekly close/high/low is available on Friday's bar)
  • expandFirst - the compressed value is expanded starting from first bar within given period (so for example weekly open is available from Monday's bar)
  • expandPoint - the resulting array gets not empty values only for the last bar within given period (all remaining bars are Null (empty)).

Based on your requirements, the mode might vary, so would the signals! Hope it helps!

1 Like

Hi Cougar,

Would you help for Time frame expand 2Hr Hist across water level and much appreciate

//MACD Indicator 2Hour across water level
TimeFrameSet( tf ) ;
Hist = ( MACD() - Signal() );
Histup = Hist > 0 ;
Histdn = Hist < 0 ;

Try something like this:

TimeFrameSet( tf );
CompCross = Cross( array1, array2 ); //Where array 1 and 2 must be compressed beforehand in same 'tf'. Also array 1, array 2 can also be static values like 0 in this case.

ExpCross = TimeFrameExpand( CompCross, tf, mode = expandHow );

Hi Cougar,

Finally got rip off the some noise, I did a simple modified on your code.

//MACD Indicator 2Hour
TimeFrameSet( tf ) ;
Hist = ( MACD() - Signal() );
Histup = Hist > 0 ;
Histdn = Hist < 0 ;
PrevHist = Ref( Hist, -1 ) ;

Histupp = TimeFrameExpand(Histup,tf);
Histdnn = TimeFrameExpand(Histdn,tf);



I appreciative your help. :slightly_smiling_face:


1 Like

Recently I was alerted by a kind user (@portfoliobuilder) about an issue in the formula I originally posted regarding the following line:

PositionScore = 100 * RSI(scoreLookBackPeriod); 

Since I'm using Ref(Buysignal, -1) - when SetTradeDelays is set at zero as per default* - I should have used the Ref() function for PositionScore as well.

As posted, it looks like the formula is using the PositionScore on the day of entry but in reality, the PositionScore from the end of the previous bar would be the correct score.

So the correct way is to use:

PositionScore = Ref( 100 * RSI(scoreLookBackPeriod), -1); // or something similar if you you other criteria

I apologize to anyone who may have tried to use the formula and got unexpected results.

In any case, this is to remind us that before putting any system into production, we must test and verify it personally, ideally paper trading it for a significant period.

To understand the impact of the my mistake, try backtesting the formula in the original wrong version versus the correct one: how much do the results change?

For this reason, for some time now, I have been a bit skeptical about the effectiveness of daily systems based exclusively on technical analysis, where a single bar offset can have a strong impact on results and, for stocks and ETFs, I favor research systems where there is a potential "edge" due to more structural market elements.

*) It would have been better to SetTradeDelays() explicitly in the formula.