September 2006
TRADERS' TIPS

Here is this month's selection of Traders' Tips, contributed by various developers of technical analysis software to help readers more easily implement some of the strategies presented in this and other issues.

You can copy these formulas and programs for easy use in your spreadsheet or analysis software. Simply "select" the desired text by highlighting as you would in any word processing program, then use your standard key command for copy or choose "copy" from the browser menu. The copied text can then be "pasted" into any open spreadsheet or other software by selecting an insertion point and executing a paste command. By toggling back and forth between an application window and the open Web page, data can be transferred with ease.

This month's tips include formulas and programs for:

  TRADESTATION: Adaptive Price Zone
  METASTOCK: Adaptive Price Zone
  eSIGNAL: Adaptive Price Zone
  AIQ: Adaptive Price Zone
  WEALTH-LAB: Adaptive Price Zone
  AMIBROKER: Adaptive Price Zone
  NEUROSHELL TRADER: Adaptive Price Zone
  INVESTOR/RT: Adaptive Price Zone
  TRADING SOLUTIONS: Adaptive Price Zone
  TRADECISION: Adaptive Price Zone
  BIOCOMP DAKOTA: Adaptive Price Zone
  MULTICHARTS: Adaptive Price Zone
  VT TRADER: Adaptive Price Zone
  ENSIGN WINDOWS: Adaptive Price Zone

or return to September 2006 Contents


TRADESTATION: Adaptive Price Zone

Lee Leibfarth's "Trading With An Adaptive Price Zone" provides an indicator and strategy for trading breakouts of a price zone that is defined by calculating the double-smoothed exponential moving average of price and the double-smoothed exponential average of the daily range.

His article already includes EasyLanguage code for performing these tasks in an indicator and strategy, both of which can be applied to a chart. Following is some EasyLanguage code to perform some of the strategy calculations in RadarScreen, a grid-type application that is part of the TradeStation platform. Terms like "buy," "sell," "sell short," and "buy to cover," which can be used only in chart-based strategies, have been replaced with variables and a function call. The function is named "RS_Trader."

FIGURE 1: TRADESTATION AND RADARSCREEN, ADAPTIVE PRICE ZONE. Here is a sample five-minute chart of PCG. The RadarScreen (left) shows calculations for the APZ strategy. The linked chart of PCG (right) displays Leibfarth's APZ strategy applied. Subplot1 displays the CurrentBar for matching with RadarScreen's bar count. Subplot 2 displays strategy values for comparison with RadarScreen calculations.


Code for both this indicator and function can be found in the EasyLanguage Library at TradeStation.com. To download this TradeStation code for this concept, search for the file "Apz.eld."
 

Indicator:  APZ_RS
inputs:
 Price( Close ),
 Period( 20 ),
 BandPct( 1.4 ),
 ADXThreshold( 30 ) ;
variables:
 DSPrice( 0 ),
 DSRange( 0 ),
 PctBand( 0 ),
 UpBand( 0 ),
 DnBand( 0 ),
 ADXValue( 0 ),
 Action( "NA" ),
 Quantity( 100 ),
 RS_NetProfit( 0 ),
 RS_OpenPositionGain( 0 ),
  RS_MarketPosition( 0 ),
 MPString( "" ),
 RS_NetBGColor( 0 ),
 RS_OpenBGColor( 0 ) ;
DSPrice = Double_Smooth_EMA( Price, Period ) ;
DSRange = Double_Smooth_EMA( Range, Period ) ;
PctBand = BandPct * DSRange ;
UpBand = DSPrice + PctBand ;
DnBand = DSPrice - PctBand ;
ADXValue = ADX( 14 ) ;
if ADXValue <= ADXThreshold then
 begin
 if Low <= DnBand then
  Action = "Buy" ;
 if High >= UpBand then
  Action = "SellShort" ;
 end
else if ADXValue > ADXThreshold then
 if RS_MarketPosition = 1 then
  Action = "Sell"
 else
  Action = "BuyToCover" ;
RS_MarketPosition = RS_Trader( Action, Quantity,
 RS_NetProfit, RS_OpenPositionGain ) ;
if RS_MarketPosition = 1 then
 MPString = "Long"
else if RS_MarketPosition = -1 then
 MPString = "Short"
else
 MPString = "Flat" ;
if RS_NetProfit > 0 then
 RS_NetBGColor = DarkGreen
else if RS_NetProfit < 0 then
 RS_NetBGColor = Red
else
 RS_NetBGColor = Black ;
if RS_OpenPositionGain > 0 then
 RS_OpenBGColor = DarkGreen
else if RS_OpenPositionGain < 0 then
 RS_OpenBGColor = Red
else
 RS_OpenBGColor = Black ;
Plot1( CurrentBar, "CurrBar" ) ;
Plot2( MPString, "Position" ) ;
Plot3( RS_NetProfit, "ClosedNet" ) ;
Plot4( RS_OpenPositionGain, "OpenNet" ) ;
SetPlotBGColor( 3, RS_NetBGColor ) ;
SetPlotBGColor( 4, RS_OpenBGColor ) ;
Function:  RS_Trader
inputs:
 Action( stringsimple ),
 Quantity( numericsimple ),
 RS_NetProfit( numericref ),
 RS_OpenPositionGain( numericref ) ;
variables:
 ActionStr( "" ),
 PriorAction( "" ),
 LCPriorAct( "" ),
 OpenPriceChg( 0 ),
 NetPriceChg( 0 ),
 OpenChg( 0 ),
 NetChg( 0 ),
 RS_MarketPosition( 0 ),
 RS_EntryPrice( 0 ),
 RS_EntryDate( 0 ),
 RS_EntryTime( 0 ) ;
ActionStr = Action ;
PriorAction = ActionStr[1] ;
LCPriorAct = LowerStr( PriorAction ) ;
OpenPriceChg = Close - RS_EntryPrice ;
NetPriceChg = RS_EntryPrice - Open ;
OpenChg = OpenPriceChg * Quantity ;
NetChg = NetPriceChg * Quantity ;
RS_MarketPosition = RS_Trader[1] ;
if "buy" = LCPriorAct or "sellshort" = LCPriorAct then
 begin
 { going long from flat }
 if "buy" = LCPriorAct and RS_MarketPosition = 0 then
  begin
  RS_OpenPositionGain = OpenChg ;
  RS_Trader = 1 ;
  end
 { going long from short }
 else if "buy" = LCPriorAct and
  RS_MarketPosition = -1 then
  begin
  RS_NetProfit = RS_NetProfit + NetChg ;
  RS_OpenPositionGain = OpenChg ;
  RS_Trader = 1 ;
  end
 { going short from flat }
 else if "sellshort" = LCPriorAct and
  RS_MarketPosition = 0 then
  begin
  RS_OpenPositionGain = Neg( OpenChg ) ;
  RS_Trader = -1 ;
  end
 { going short from long }
 else if "sellshort" = LCPriorAct and
  RS_MarketPosition = 1 then
  begin
  RS_NetProfit = RS_NetProfit - NetChg ;
  RS_OpenPositionGain = Neg( OpenChg ) ;
  RS_Trader = -1 ;
  end ;
 RS_EntryPrice = Open ;
 RS_EntryDate = Date ;
 RS_EntryTime = Time ;
 end
else if "sell" = LCPriorAct or "buytocover" = LCPriorAct
 then
 begin
 { going from long to flat }
 if "sell" = LCPriorAct and RS_MarketPosition = 1
  then
  begin
  RS_NetProfit = RS_NetProfit - NetChg ;
  RS_OpenPositionGain = 0 ;
  RS_Trader = 0 ;
  end
 { going from short to flat }
 else if "buytocover" = LCPriorAct and
  RS_MarketPosition = -1 then
  begin
  RS_NetProfit = RS_NetProfit + NetChg ;
  RS_OpenPositionGain = 0 ;
  RS_Trader = 0 ;
  end ;
 RS_EntryPrice = 0 ;
 RS_EntryDate = 0 ;
 RS_EntryTime = 0 ;
 end
else if "buy" <> LCPriorAct
 and "sell" <> LCPriorAct
 and "sellshort" <> LCPriorAct
 and "buytocover" <> LCPriorAct
then
 begin
 if RS_MarketPosition = 1 then
  RS_OpenPositionGain = OpenChg ;
 if RS_MarketPosition = -1 then
  RS_OpenPositionGain = Neg( OpenChg ) ;
 end
else
 RS_Trader = RS_Trader[1] ;
--Mark Mills
TradeStation Securities, Inc.
A subsidiary of TradeStation Group, Inc.
www.TradeStationWorld.com
GO BACK

METASTOCK: Adaptive Price Zone

Lee Leibfarth's article, "Trading With An Adaptive Price Zone," introduces a new indicator and suggests a trading system for it. The formula for the indicator and the instructions on adding it to MetaStock follow.
 

To enter these indicators into MetaStock:
1. In the Tools menu, select Indicator Builder.
2. Click New to open the Indicator Editor for a new indicator.
3. Type the name of the formula
4. Click in the larger window and type in the formula.
5. Click Ok to close the Indicator Editor.
Name: Instantaneous Trendline
Formula:
x:=Input("time periods", 2, 200, 20);
y:=Input("band percentage",0.1, 50, 1.4);
dsema:=Mov(Mov(C,x,E),x,E);
shift:=Mov(Mov(H-L,x,E),x,E);
dsema+(y*shift);
dsema-(y*shift);
This indicator will prompt for the time periods and the percentage shift of the bands. The
suggested trading system and instructions for creating it in MetaStock are:

1. Select Tools > the Enhanced System Tester
2. Click "New"
3. Enter the name, "Adaptive Price Zone Strategy"
4. Select the Buy Order tab and enter the following formula:
x:=20;
y:= 1.4;
dsema:=Mov(Mov(C,x,E),x,E);
shift:=Mov(Mov(H-L,x,E),x,E);
top:=dsema+(y*shift);
bot:=dsema-(y*shift);
ADX(14) < 30 AND L<bot
Select the "Sell" order tab and enter the following formula:
x:=20;
y:= 1.4;
dsema:=Mov(Mov(C,x,E),x,E);
shift:=Mov(Mov(H-L,x,E),x,E);
top:=dsema+(y*shift);
bot:=dsema-(y*shift);
ADX(14) >= 30 OR H>top
Select the "Sell short" order tab and enter the following formula:
x:=20;
y:= 1.4;
dsema:=Mov(Mov(C,x,E),x,E);
shift:=Mov(Mov(H-L,x,E),x,E);
top:=dsema+(y*shift);
bot:=dsema-(y*shift);
ADX(14) < 30 AND H>top
Select the "Buy to cover" order tab and enter this formula:
x:=20;
y:= 1.4;
dsema:=Mov(Mov(C,x,E),x,E);
shift:=Mov(Mov(H-L,x,E),x,E);
top:=dsema+(y*shift);
bot:=dsema-(y*shift);
ADX(14) >= 30 OR L<bot


Click OK to close the system editor.

--William Golson
Equis International


GO BACK


eSIGNAL: Adaptive Price Zone

For this month's Traders' Tips article by Lee Leibfarth, "Trading With An Adaptive Price Zone," we've provided two formulas: "AdaptivePriceZone.efs" and "Apz_Strategy.efs."

Both studies contain formula parameters for the period length and band percentage that may be configured through the Edit Studies option in the Advanced Chart. Apz_Strategy.efs has additional formula parameters for the ADX and its corresponding threshold value. The strategy study is compatible for backtesting and real-time usage.

A sample implementation is shown in Figures 2 and 3. To discuss this study or download a complete copy of the formula, please visit the EFS Library Discussion Board forum under the Bulletin Boards link at www.esignalcentral.com.
 

/***************************************
Provided By : eSignal (c) Copyright 2006
Description:  Trading With An Adaptive Price Zone
              by Lee Leibfarth
Version 1.0  07/06/2006
Notes:
* Sept 2006 Issue of Stocks and Commodities Magazine
* Study requires version 8.0 or higher.
Formula Parameters:                 Defaults:
Period                              20
Band Percent                        2
***************************************/
function preMain() {
    setPriceStudy(true);
    setStudyTitle("Adaptive Price Zone Indicator ");
    setCursorLabelName("Upper Band", 0);
    setCursorLabelName("Lower Band", 1);
    setDefaultBarThickness(2, 0);
    setDefaultBarThickness(2, 1);
    setDefaultBarStyle(PS_DOT, 0);
    setDefaultBarStyle(PS_DOT, 1);
   
    var fp1 = new FunctionParameter("nPeriods", FunctionParameter.NUMBER);
        fp1.setName("Period");
        fp1.setLowerLimit(1);
        fp1.setDefault(20);
    var fp2 = new FunctionParameter("nBandPct", FunctionParameter.NUMBER);
        fp2.setName("Band Percent");
        fp2.setLowerLimit(0);
        fp2.setDefault(2);
}
var bVersion = null;
var bInit = false;
var xAPZ = null;
var xAPZ_Upper = null;  // Upper Band
var xAPZ_Lower = null;  // Lower Band
function main(nPeriods, nBandPct) {   
    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return;   
    if (bInit == false) {
        xAPZ = efsInternal("calcAPZ", nPeriods, nBandPct);
        bInit = true;
    }
   
    if (xAPZ_Upper == null) xAPZ_Upper = getSeries(xAPZ, 0);  // Upper Band
    if (xAPZ_Lower == null) var xAPZ_Lower = getSeries(xAPZ, 1);  // Lower Band
    var nAPZ_Upper = xAPZ_Upper.getValue(0);
    var nAPZ_Lower = xAPZ_Lower.getValue(0);
    if (nAPZ_Upper == null || nAPZ_Lower == null) return;
    if (high(0) > nAPZ_Upper) {
        drawShape(Shape.CIRCLE, AboveBar1, Color.blue, rawtime(0));
    } else if (low(0) < nAPZ_Lower) {
        drawShape(Shape.CIRCLE, BelowBar1, Color.blue, rawtime(0));
    }
   
    return new Array(nAPZ_Upper, nAPZ_Lower);
}
var xHL = null;
function calcAPZ(nPeriods, nBandPct) {
    if (xHL == null) xHL = efsInternal("calcHL");
    if (isNaN(xHL.getValue(0))) return;
   
    //nPeriods = Math.round(Math.sqrt(nPeriods));
    nPeriods = Math.ceil(Math.sqrt(nPeriods));
    var Value1 = ema(nPeriods, ema(nPeriods), 0);
    var Value2 = ema(nPeriods, ema(nPeriods, xHL), 0);
    if (Value1 == null || Value2 == null) return;
   
    var UpBand = nBandPct * Value2 + Value1;
    var DnBand = Value1 - nBandPct * Value2;
    if (UpBand == null || DnBand == null) return;
   
    return new Array(UpBand, DnBand);
}
function calcHL() {
    return high(0) - low(0);
}
function verify() {
    var b = false;
    if (getBuildNumber() < 779) {
        drawTextAbsolute(5, 35, "This study requires version 8.0 or later.",
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "error");
        drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=https://www.esignal.com/download/default.asp",
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "upgrade");
        return b;
    } else {
        b = true;
    }
   
    return b;
}
/***************************************
Provided By : eSignal (c) Copyright 2006
Description:  Trading With An Adaptive Price Zone
              by Lee Leibfarth
Version 1.0  07/06/2006
Notes:
* Sept 2006 Issue of Stocks and Commodities Magazine
* Study requires version 8.0 or higher.
* Study is designed for Back Testing.
Formula Parameters:                 Defaults:
Period                              20
Band Percent                        2
ADX Period                          14
ADX Smoothing                       14
ADX Threshold                       30
***************************************/
function preMain() {
    setPriceStudy(true);
    setStudyTitle("Adaptive Price Zone Strategy ");
    setShowTitleParameters(false);
    setCursorLabelName("Upper Band", 0);
    setCursorLabelName("Lower Band", 1);
    setCursorLabelName("ADX", 2);
    setDefaultBarFgColor(Color.blue, 0);
    setDefaultBarFgColor(Color.blue, 1);
    setDefaultBarFgColor(Color.green, 2);
    setDefaultBarThickness(2, 0);
    setDefaultBarThickness(2, 1);
    setDefaultBarStyle(PS_DOT, 0);
    setDefaultBarStyle(PS_DOT, 1);
    setDefaultFont("Ariel", 12);
   
    var fp1 = new FunctionParameter("nPeriods", FunctionParameter.NUMBER);
        fp1.setName("Period");
        fp1.setLowerLimit(1);
        fp1.setDefault(20);
    var fp2 = new FunctionParameter("nBandPct", FunctionParameter.NUMBER);
        fp2.setName("Band Percent");
        fp2.setLowerLimit(0);
        fp2.setDefault(2);
    var fp3 = new FunctionParameter("nADXPeriods", FunctionParameter.NUMBER);
        fp3.setName("ADX Period");
        fp3.setLowerLimit(1);
        fp3.setDefault(14);
    var fp4 = new FunctionParameter("nADXSmoothing", FunctionParameter.NUMBER);
        fp4.setName("ADX Smoothing");
        fp4.setLowerLimit(1);
        fp4.setDefault(14);
    var fp5 = new FunctionParameter("nADXThreshold", FunctionParameter.NUMBER);
        fp5.setName("ADX Threshold");
        fp5.setLowerLimit(0);
        fp5.setDefault(30);
}
var bVersion = null;
var bInit = false;
var bBackTest = true;
var vPosition = null;
var xAPZ = null;
var xAPZ_Upper = null;  // Upper Band
var xAPZ_Lower = null;  // Lower Band
function main(nPeriods, nBandPct, nADXPeriods, nADXSmoothing, nADXThreshold) {   
    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return;   
    if (bInit == false) {
        xAPZ = efsInternal("calcAPZ", nPeriods, nBandPct);
        bInit = true;
    }
   
    if (xAPZ_Upper == null) xAPZ_Upper = getSeries(xAPZ, 0);  // Upper Band
    if (xAPZ_Lower == null) var xAPZ_Lower = getSeries(xAPZ, 1);  // Lower Band
    var nAPZ_Upper = xAPZ_Upper.getValue(0);
    var nAPZ_Lower = xAPZ_Lower.getValue(0);
    var nAPZ_Upper_1 = xAPZ_Upper.getValue(-1);
    var nAPZ_Lower_1 = xAPZ_Lower.getValue(-1);
    var nADX_0 = adx(nADXPeriods, nADXSmoothing, 0);
    var nADX_1 = adx(nADXPeriods, nADXSmoothing, -1);
    if (nAPZ_Upper_1 == null || nAPZ_Lower_1 == null || nADX_1 == null) return;
    if (getCurrentBarIndex() == 0) bBackTest = false;
   
    if (vPosition != null && nADX_1 > nADXThreshold) {  // Exit signal
        if (vPosition == "long") {
            drawText("Sell", AboveBar3, Color.red, Text.BOLD|Text.CENTER, "t"+rawtime(0));
            drawShape(Shape.DOWNARROW, AboveBar2, Color.red, "s"+rawtime(0));
            vPosition = null;
            Alert.playSound("ding.wav");
            if (bBackTest == true) {
                Strategy.doSell("Sell", Strategy.MARKET, Strategy.THISBAR);
            }
        } else if (vPosition == "short") {
            drawText("Cover", BelowBar3, Color.red, Text.BOLD|Text.CENTER, "t"+rawtime(0));
            drawShape(Shape.UPARROW, BelowBar2, Color.red, "s"+rawtime(0));
            vPosition = null;
            Alert.playSound("ding.wav");
            if (bBackTest == true) {
                Strategy.doCover("Cover", Strategy.MARKET, Strategy.THISBAR);
            }
        }
    } else if (nADX_1 <= nADXThreshold) {  // Entry signal    

        if (vPosition != "short" && high(-1) >= nAPZ_Upper_1) { // Short signal
            vPosition = "short";
            drawText("Short", AboveBar3, Color.blue, Text.BOLD|Text.CENTER, "t"+rawtime(0));
            drawShape(Shape.DOWNARROW, AboveBar2, Color.blue, "s"+rawtime(0));
            Alert.playSound("pop.wav");
            if (bBackTest == true) {
                Strategy.doShort("Short", Strategy.MARKET, Strategy.THISBAR);
            }
        }
        if (vPosition != "long" && low(-1) <= nAPZ_Lower_1) { // Long signal
            vPosition = "long";
            drawText("Long", BelowBar3, Color.blue, Text.BOLD|Text.CENTER, "t"+rawtime(0));
            drawShape(Shape.UPARROW, BelowBar2, Color.blue, "s"+rawtime(0));
            Alert.playSound("pop.wav");
            if (bBackTest == true) {
                Strategy.doLong("Long", Strategy.MARKET, Strategy.THISBAR);
            }
        }
    }
   
    return new Array(nAPZ_Upper, nAPZ_Lower, nADX_0.toFixed(6));
}
var xHL = null;
function calcAPZ(nPeriods, nBandPct) {
    if (xHL == null) xHL = efsInternal("calcHL");
    if (isNaN(xHL.getValue(0))) return;
   
    //nPeriods = Math.round(Math.sqrt(nPeriods));
    nPeriods = Math.ceil(Math.sqrt(nPeriods));
    var Value1 = ema(nPeriods, ema(nPeriods), 0);
    var Value2 = ema(nPeriods, ema(nPeriods, xHL), 0);
    if (Value1 == null || Value2 == null) return;
   
    var UpBand = nBandPct * Value2 + Value1;
    var DnBand = Value1 - nBandPct * Value2;
    if (UpBand == null || DnBand == null) return;
   
    return new Array(UpBand, DnBand);
}
function calcHL() {
    return high(0) - low(0);
}
function verify() {
    var b = false;
    if (getBuildNumber() < 779) {
        drawTextAbsolute(5, 35, "This study requires version 8.0 or later.",
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "error");
        drawTextAbsolute(5, 20, "Click HERE to upgrade.@URL=https://www.esignal.com/download/default.asp",
            Color.white, Color.blue, Text.RELATIVETOBOTTOM|Text.RELATIVETOLEFT|Text.BOLD|Text.LEFT,
            null, 13, "upgrade");
        return b;
    } else {
        b = true;
    }
   
    return b;
}
FIGURE 2: eSIGNAL, ADAPTIVE PRICE ZONE INDICATOR. Here is a demonstration of Lee Leibfarth's adaptive price zone indicator on the S&P 500 emini futures contract in eSignal.
 


FIGURE 3: eSIGNAL, ADAPTIVE PRICE ZONE STRATEGY. Here is a demonstration of Lee Leibfarth's adaptive price zone system on the S&P 500 emini futures contract in eSignal.
 

--Jason Keck
eSignal, a division of Interactive Data Corp.
800 815-8256, www.esignalcentral.com


GO BACK


AIQ: Adaptive Price Zone

Here is the AIQ code for Lee Leibfarth's adaptive price zone indicator and the related trading system.

Since AIQ is well suited to simulate trading a portfolio of stocks, I tested the system on the NASDAQ 100 list of stocks using the Portfolio Manager. I did a rough optimization on the long side of the trading system using the bullish period from 10/15/2002 to 7/11/2006. I used the ADX value descending to pick three trades per day, 10% each, and a maximum of 10 open positions. The results of the first test show that the long side of the system outperforms the NASDAQ 100 index (see Figure 4, which shows an average return of 28.7% with a Sharpe ratio of 1.35).

FIGURE 4: AIQ SYSTEMS, ADAPTIVE PRICE ZONE. Testing the APZ strategy on the long side during a bullish period produced good results, outperforming the NASDAQ 100 index and having an average return of 28.7% with a Sharpe ratio of 1.35.


I then tested the short side, using the parameters from the first test, over the bearish period 9/01/2000 to 10/15/2002 and again, the short side outperformed the NASDAQ 100 index (see Figure 5, which shows an average return of 36.3% with a Sharpe ratio of 1.07). However, neither the long nor the short side of the system performed well when the test periods were reversed. The long side, when tested during the bearish period from 9/01/2000 to 10/15/2002, showed an average loss of 22.4% with a Sharpe ratio of -0.58. The short side, when tested during the bullish period from 10/15/2002 to 07/11/2006, showed an average loss of 24.6% with a Sharpe ratio of -1.24. Before trading this system on stocks, it appears that a market-timing filter should be added.

FIGURE 5: AIQ SYSTEMS, ADAPTIVE PRICE ZONE. Testing the APZ strategy on the short side during a bearish period also produced good results, outperforming the NASDAQ 100 index and having an average return of 36.3% with a Sharpe ratio of 1.07.


This code can be downloaded from the AIQ website at www.aiqsystems.com.
 

!! TRADING WITH AN ADAPTIVE PRICE ZONE
!  Author: Lee Leibfarth, TASC September, 2006
!  Coded by: Richard Denning 07/06/06
! CODING ABBREVIATIONS:
H is [high].
L is [low].
C is [close].
Price is C.
LL1 is 65.
BB1 is 1.8.
PP1 is round(sqrt(LL1)).
dsEMA is expavg(expavg(Price,PP1),PP1).
RdsEMA is expavg(expavg(H - L,PP1),PP1).
UpAPZ is dsEMA + BB1 * RdsEMA.
DnAPZ is dsEMA - BB1 * RdsEMA.
! COLOR BAR STUDY
Green if L <= DnAPZ and [ADX] < 30.
Red if H >= UpAPZ and [ADX] < 30.
! TRADING SYSTEM
ADXco is 30.
! Note: set ADX value to default of 14.
LE if [ADX] <= ADXco and L <= DnAPZ.
LX if  [ADX] > ADXco or H >= UpAPZ.
SE if [ADX] <= ADXco and H >= UpAPZ.
SX if  [ADX] > ADXco or L <= DnAPZ.
! RANKING
ADX is [ADX].
RC30 is (C / valresult(C,30) - 1) * 100.
--Richard Denning
AIQ Systems, www.aiqsystems.com
richard.denning@earthlink.net


GO BACK


WEALTH-LAB: Adaptive Price Zone

Here is the WealthScript code necessary to recreate the adaptive price zone as well as a testing strategy based on the ideas expressed in Lee Leibfarth's article in this issue.

As suggested in the article, we included an additional exit if the trade turns unprofitable after three bars. To detect if the ADX is moving up or down, we felt it necessary to add a two-pole Gaussian filter for smoothing. Finally, the script is "optimizer-ready" so that you can investigate how changing the default values for some variables can affect the profit outcome of the strategy. A sample chart is shown in Figure 6.

FIGURE 6: WEALTH-LAB, ADAPTIVE PRICE ZONE. We didn't find the strategy particularly profitable trading stocks on a daily basis, but some trades like the one shown here quite accurately catch the meaty part of a reversal.
 

WealthScript code:

{#OptVar1 20;10;50;5}
{#OptVar2 20;16;40;4}
{$I 'EMA2'}
{$I 'Gaussian'}
const ADX_Threshold = 30;
var Bar, p, dsEMA, dsAdapt, Uband, Lband, EMAPer, ADXPane, hADX: integer;
var BandPct: float;
var ExitSig: string;
EMAPer := #OptVar1;
BandPct := #OptVar2 / 10;
function dsEMASeries( Series, Period: integer ): integer;
begin
  var srPer: float = Sqrt( Period );
  Result := EMA2Series( EMA2Series( Series, srPer ), srPer );
end;
{ Create and plot indicator series }
dsEMA := dsEMASeries( #Close, EMAPer );
dsAdapt := dsEMASeries( SubtractSeries( #High, #Low ), EMAPer );
dsAdapt := MultiplySeriesValue( dsAdapt, BandPct );
Uband := AddSeries( dsEMA, dsAdapt );
Lband := SubtractSeries( dsEMA, dsAdapt );
SetDescription( UBand, 'Upper APZ' );
SetDescription( LBand, 'Lower APZ' );
PlotSeries( Uband, 0, #Blue, #Dotted );
PlotSeries( Lband, 0, #Red, #Dotted );
ADXPane := CreatePane( 75, true, true );
hADX := GaussianSeries( ADXSeries( 14 ), 13, 2 );
PlotSeriesLabel( hADX, ADXPane, 550, #Thick, 'ADX(14)' );
DrawHorzLine( ADX_Threshold, ADXPane, #Red, #Thin );
{ Execute trading system }
for Bar := EMAPer * 3 to BarCount - 1 do
begin
  if LastPositionActive then
  begin
    p := LastPosition;
    ExitSig := '';
    if ( Bar + 1 - PositionEntryBar( p ) > 3 )
    and ( PositionOpenProfitPct( Bar, p ) <= -1 ) then
      ExitSig := 'No Reversal'
    else if CrossOverValue( Bar, hADX, 30 ) then
      ExitSig := 'ADX Exit';
    if ExitSig <> '' then
      if PositionLong( p ) then
        SellAtMarket( Bar + 1, p, ExitSig )
      else
        CoverAtMarket( Bar + 1, p, ExitSig );
  end
  else if ( ROC( Bar, hADX, 2 ) < 0 ) and ( @hADX[Bar] < ADX_Threshold ) then
    if CrossUnder( Bar, #Low, LBand ) then
      BuyAtMarket( Bar + 1, '' )
    else if CrossOver( Bar, #High, UBand ) then
      ShortAtMarket( Bar + 1, '' );
end;
-- Robert Sucher
www.wealth-lab.com
GO BACK

AMIBROKER: Adaptive Price Zone

In "Trading With An Adaptive Price Zone," author Lee Leibfarth presents a trading technique that uses adaptive bands based on the double-smoothed exponential moving average and the classic ADX indicator.

Implementing the adaptive price zone technique using AmiBroker Formula Language is easy and straightforward. Listing 1 shows ready-to-use code. The formula is for both the indicator and the trading system. A sample chart is shown in Figure 7.

FIGURE 7: AMIBROKER, ADAPTIVE PRICE ZONE. This AmiBroker screenshot shows a daily price chart of the S&P 500 continuous contract with adaptive price zone bands and trade entry/exit arrows (upper pane) and the ADX indicator (lower pane).
LISTING 1
// Adaptive Price Zone Indicator & system
////////////////////////////////
function DblSmoothEMA( price, Length )
{
   period = IIf( Length < 0, 1, sqrt( Length ) );
   smooth = 2 / ( period + 1 );
   return AMA( AMA( price, smooth ), smooth );
}
price = ParamField("Price");
period = Param("period", 20, 2, 100 );
BandPct = Param("width[%]", 1.4, 0.1, 4, 0.1 );
DsEMA = DblSmoothEMA( price, period );
RangeDsEMA = DblSmoothEMA( H - L, period );
UpBand = BandPct * RangeDsEMA + DsEMA;
DnBand = DsEMA - BandPct * RangeDsEMA ;
Plot( C, "Price", colorBlack, styleBar );
Plot( UpBand , "UpBand", colorLightGrey );
Plot( DnBand , "DownBand", colorLightGrey );
// you may uncomment lines below to get 'cloud' chart
// if you are using version 4.80 or higher
// PlotOHLC( UpBand, UpBand, DnBand, DnBand, "Band",
// ColorRGB( 245,245,255), styleCloud );
SetTradeDelays( 1, 1, 1, 1 );
ADXThshold = 30;
ADXValue = ADX( 14 );
Buy = ADXValue <= ADXThshold AND Low <= DnBand;
Short = ADXValue <= ADXThshold AND High >= UpBand;
Sell = Cover = ADXValue > ADXThshold;
if( Status("action") == actionIndicator )
{
 Equity(2);
 PlotShapes( Buy * shapeUpArrow, colorGreen, 0, DnBand, -24 );
 PlotShapes( Sell * shapeDownArrow, colorRed, 0, UpBand, -24 );
 PlotShapes( Short * shapeHollowDownArrow, colorRed, 0, UpBand, -24 );
 PlotShapes( Cover * shapeHollowUpArrow, colorGreen, 0, DnBand, -24 );
}
--Tomasz Janeczko, AmiBroker.com
www.amibroker.com


GO BACK


NEUROSHELL TRADER: Adaptive Price Zone

The adaptive price zones described by Lee Leibfarth in his article in this issue can be easily implemented in NeuroShell Trader by combining a few of NeuroShell Trader's 800+ indicators. To implement the excursion indicators, select "New Indicator ..." from the Insert menu and use the Indicator Wizard to create the following indicators:
 

Upper Band:
     Add2 ( ExpAvg(ExpAvg(Close,4),4), Mult2( 1.4, ExpAvg(ExpAvg(Subtract(High,Low),4),4) ) )
Lower Band:
     Subtract ( ExpAvg(ExpAvg(Close,4),4), Mult2( 1.4, ExpAvg(ExpAvg(Subtract(High,Low),4),4) ) )
To recreate the adaptive price zone strategy, select "New Trading Strategy ..." from the Insert menu 
and enter the following entry and exit conditions in the appropriate locations of the Trading 
Strategy Wizard:

Generate a buy long MARKET order if ALL of the following are true:
 A<=B ( ADX(High, Low, Close, 14, 14), 30 )
 A<=B ( Low, LowerBand  )
Generate a sell long MARKET order if ALL of the following are true:
 A>B ( ADX(High, Low, Close, 14, 14), 30 )
Generate a sell short MARKET order if ALL of the following are true:
 A<=B ( ADX(High, Low, Close, 14, 14), 30 )
 A>=B ( Low, UpperBand  )
Generate a cover short MARKET order if ALL of the following are true:
 A>B ( ADX(High, Low, Close, 14, 14), 30 )


A sample chart is shown in Figure 8.

FIGURE 8: NEUROSHELL, ADAPTIVE PRICE ZONE. This sample NeuroShell Trader chart displays the trend adaptive price zone indicator and system.


If you have NeuroShell Trader Professional, you can also choose whether the system parameters should be optimized. After backtesting the trading strategy, use the "Detailed Analysis ..." button to view the backtest and trade-by-trade statistics for the adaptive price zone trading system.

Users of NeuroShell Trader can go to the STOCKS & COMMODITIES section of the NeuroShell Trader free technical support website to download a copy of this or previous Traders' Tips.

--Marge Sherald, Ward Systems Group, Inc.
301 662-7950, sales@wardsystems.com
www.neuroshell.com
GO BACK

INVESTOR/RT: Adaptive Price Zone

Figure 9 shows an Investor/RT implementation of Lee Leibfarth's adaptive price zone (APZ) bands on a one-minute chart of the S&P emini. The upper and lower bands are constructed using custom indicators with the following syntax:

FIGURE 9: INVESTOR/RT, ADAPTIVE PRICE ZONE. This Investor/RT one-minute bar chart of ES U6 displays the APZ upper and lower bands in blue, along with signal markers when price drops below the lower band (buy) or rises above the upper band (sell).
APZ Upper Band
TRIP + 2 * TRIP_ATR
APZ Lower Band
TRIP - 2 * TRIP_ATR


The Trip token represents the triple smoothing indicator, but it also has an option for double smoothing instead of triple smoothing.

This chart can be quickly imported into Investor/RT, along with the associated custom indicators and signal markers, by visiting the Investor/RT Charts page at the following URL:

https://www.linnsoft.com/charts/
More information on Investor/RT's triple smoothing indicator can be found at:
 
https://www.linnsoft.com/tour/techind/trip.htm
--Chad Payne, Linn Software
info@linnsoft.com, www.linnsoft.com
GO BACK

TRADING SOLUTIONS: Adaptive Price Zone

In his article "Trading With An Adaptive Price Zone," Lee Leibfarth presents a trading system based on an adaptive price zone and the average directional movement indicator.

The following functions can be entered into TradingSolutions. These functions are also available as a function file that can be downloaded from the TradingSolutions website (www.tradingsolutions.com) in the Solution Library section.
 

Function Name: Double Smooth EMA
Short Name: DSEMA
Inputs: Data, Period
EMA (EMA (Data, Sqrt (Period)), Sqrt (Period))
Function Name: Adaptive Price Zone - Upper Band
Short Name: APZ_Upper
Inputs: Close, High, Low, Period, BandPct
Add (DSEMA (Close, Period), Mult (BandPct, DSEMA (Sub (High, Low), Period)))
Function Name: Adaptive Price Zone - Lower Band
Short Name: APZ_Upper
Inputs: Close, High, Low, Period, BandPct
Sub (DSEMA (Close, Period), Mult (BandPct, DSEMA (Sub (High, Low), Period)))
System Name: Adaptive Price Zone Strategy
Inputs: Close, High, Low, Period, BandPct, ADX Threshold, DX Period, ADX Smoothing Period
Enter Long:
LE (ADX (Close, High, Low, DX Period, ADX Smoothing ), ADX Threshold )
LE (Low, APZ_Lower (Close, High, Low, Period, BandPct))
Enter Short:
LE (ADX (Close, High, Low, DX Period, ADX Smoothing ), ADX Threshold )
GE (High, APZ_Upper (Close, High, Low, Period, BandPct))
Exit Long:
System_IsLong( )
GT (ADX (Close, High, Low, DX Period, ADX Smoothing ), ADX Threshold )
Exit Short:
System_IsShort( )
GT (ADX (Close, High, Low, DX Period, ADX Smoothing ), ADX Threshold )


These individual formulas can be used to create fields that can be displayed in a chart with the closing price. They can also be used as optimizable inputs to a neural network or as optimizable elements of entry/exit system rules.

--Gary Geniesse
NeuroDimension, Inc.
800 634-3327, 352 377-5144
www.tradingsolutions.com
GO BACK

TRADECISION: Adaptive Price Zone

Lee Leibfarth's article, "Trading With An Adaptive Price Zone," introduces a technique for analyzing price action and finding key reversal points in a ranging market to help find trading opportunities.

Tradecision requires two separate indicators to implement the idea presented in the article. By using the Indicator Builder, the user can create the adaptive price zone lower band and adaptive price zone upper band indicators (Figure 10). Following is the code:

 
FIGURE 10: TRADECISION, ADAPTIVE PRICE ZONE. On a one-minute chart of the emini Russell 2000 futures contract (AB #F), we can see how the APZ technique helps point out key reversals in the market. The red and green arrows represent signals of the adaptive price zone strategy applied to the chart.
Adaptive Price Zone Lower Band
Input
     Price:  "Price", Close;
     Period: "Period", 20;
     BandPc: "Band Percent", 2;
End_input
Var
  Per := SquareRoot(Period); { Adaptive period }
  Pr  := Ema( Ema( Price, Per), Per);
  HL  := Ema( Ema( H-L, Per), Per);
End_var
return Pr - BandPc * HL;
Adaptive Price Zone Upper Band
Input
     Price:  "Price", Close;
     Period: "Period", 20;
     BandPc: "Band Percent", 2;
End_input
Var
  Per := SquareRoot(Period); { Adaptive period }
  Pr  := Ema( Ema( Price, Per), Per);
  HL  := Ema( Ema( H-L, Per), Per);
End_var
return Pr + BandPc * HL;
Using Strategy Builder, we can build the adaptive price zone strategy by combining the technique with other indicator-based and money-management rules.

To import the indicators and strategy into Tradecision, visit the Traders' Tips area at https://tradecision.com/support/tasc_tips/tasc_traders_tips.htm.

--Alex Grechanowski, Alyuda Research, Inc.
alex@alyuda.com, 347 416-6083
www.alyuda.com, www.tradecision.com
GO BACK

BIOCOMP DAKOTA: Adaptive Price Zone

In "Trading With An Adaptive Price Zone," Lee Leibfarth shows us how to create a market model using an adaptive trade zone. In BioComp Dakota With Swarm Technology, you can easily recreate this trading system by calling the built-in ADX and AMA functions within ScriptBots. Dakota's VB Script code for Leibfarth's trading system is rather simple:
 

Function Script_CreateSignal(Prices())
  Dim RangeBand
  Dim SmoothedClose
  Dim ADX
  Dim Signal
  PriceCtr = PriceCtr+1
  ReDim Preserve HighHistory(PriceCtr)
  ReDim Preserve LowHistory(PriceCtr)
  ReDim Preserve CloseHistory(PriceCtr)
  ReDim Preserve RangeHistory(PriceCtr)
  HighHistory(PriceCtr)=Prices(HIGH)
  LowHistory(PriceCtr)=Prices(LOW)
  CloseHistory(PriceCtr)=Prices(CLOSE)
  RangeHistory(PriceCtr)=Prices(HIGH)-Prices(LOW)
  RangeBand = 2 * Dakota.AMA(RangeHistory,ParameterValue(1))
  SmoothedClose = Dakota.AMA(CloseHistory,ParameterValue(1))
  ADX = Dakota.ADX(HighHistory, LowHistory, CloseHistory, 14)'ParameterValue(1))
  If Prices(CLOSE) > (SmoothedClose + RangeBand) and ADX < 30 then
    Signal = 1
  ElseIf Prices(CLOSE) < (SmoothedClose - RangeBand) and ADX < 30 then
    Signal = -1
  else
    Signal = PrevSignal
  End If
  PrevSignal = Signal
  Script_CreateSignal = Signal
  Exit Function
End Function


Dakota users can download this trading bot from the Download Center in the new Profit/Dakota forums.

--Carl Cook
BioComp Systems, Inc., 952 746-5761
www.biocompsystems.com/products/Dakota/
GO BACK

MULTICHARTS: Adaptive Price Zone

MultiCharts' scripting language is fully compatible with TradeStation's EasyLanguage. This means that you can use the TradeStation code for Lee Leibfarth's techniques right from the sidebar to his article in this issue, "Trading With An Adaptive Price Zone." The result of applying both the indicator and the strategy to MultiCharts is demonstrated in Figure 11.

FIGURE 11: MULTICHARTS, ADAPTIVE PRICE ZONE. On this chart of the S&P emini continuous contract, you can see how the strategy fared.


To discuss this article or download a complete copy of the formulas, please visit our discussion forum at forum.tssupport.com.

--Stanley Miller
TS Support, Llc
www.tssupport.com
GO BACK

VT TRADER: Adaptive Price Zone Indicator

Lee Leibfarth's article in this issue, "Trading With An Adaptive Price Zone," introduces the adaptive price zone (APZ) indicator. The APZ is a set of bands based on a double-smoothed exponential moving average that creates a channel surrounding the average market price. It is designed to help traders find short-term trading opportunities by identifying potential price reversal points in ranging markets.

The article goes on to discuss the value of the ADX indicator for determining the trendiness of the market and outlines a trading methodology based on the APZ and the ADX indicators. Buy signals are generated when the ADX is less than 30 and price crosses above the upper band of the APZ indicator; sell signals are generated while the ADX is less than 30 and price crosses below the lower band of the APZ indicator.

We will offer the adaptive price zone indicator as well as an accompanying trading system for download in our user forums. You can visit the VT Trader website at www.cmsfx.com or the STOCKS & COMMODITIES website at www.Traders.com and see the September 2006 Traders' Tips area. To attach the APZ indicator to a chart (Figure 12), click the right mouse button within the chart window and then select "Add Indicators" -> "TASC - 09/2006 - Adaptive Price Zone" from the indicator list.

FIGURE 12: VT TRADER, ADAPTIVE PRICE ZONE INDICATOR. This chart demonstrates the adaptive price zone indicator overlaid on the USD/CAD 30-minute candlestick chart .
An abbreviated listing of the VT Trader code is shown here:
 
In the Formula Bookmark, copy and paste the following formula:
{Provided By: Visual Trading Systems, LLC (c) Copyright 2006}
{Description: Doing The Cross-Street Shuffle - Trading With An Adaptive Price Zone by Lee Leibfarth}
{Notes: September 2006 Issue - Doing The Cross-Street Shuffle - Trading With An Adaptive Price Zone}
{vt_APZ Version 1.0}
DoubleEMA:= mov(mov(mPr,mPer,mTp),mPer,mTp);
DoubleEMADiff:= mov(mov((H-L),mPer,mTp),mPer,mTp);
UpperBand:= BandPct * DoubleEMADiff + DoubleEMA;
LowerBand:= DoubleEMA - BandPct * DoubleEMADiff;
--Chris Skidmore
Visual Trading Systems, LLC (courtesy of CMS Forex)
(866) 51-CMSFX, trading@cmsfx.com
www.cmsfx.com


GO BACK


ENSIGN WINDOWS: Adaptive Price Zone

Here is Ensign Software's implementation of Lee Leibfarth's adaptive price zone strategy as described in his article in this issue. Figure 13 demonstrates using Ensign's Design Your Own Study feature to recreate the indicator.

FIGURE 13: ENSIGN WINDOWS, ADAPTIVE PRICE ZONE. You can use Ensign Window's Design Your Own Study feature to implement Lee Leibfarth's adaptive price zone strategy.


Figure 14 demonstrates some results from the system. The system does poorly in trending markets, such as was the case in 2003. A few of the signals and 2003 trades are documented in Figure 15. However, knowing whether the market is trending or nontrending is often a matter of hindsight. The chart in 2003 from July through December did not appear to be trending, and the ADX for that time period implied it was nontrending by staying below 25. Yet there were no profitable trades in 2003.

FIGURE 14: ENSIGN WINDOWS, ADAPTIVE PRICE ZONE TRADE SUMMARY. Here is a summary of trades from November 1997 through July 2006 after applying the adaptive price zone indicator.
 
 

FIGURE 15: ENSIGN WINDOWS, ADAPTIVE PRICE ZONE. Here is an example of how the adaptive price zone strategy would have lost money during the trending market of 2003.

Though Leibfarth calls his study an adaptive price zone, it is not really an adaptive indicator. "Adaptive" implies the study uses a self-adjusting parameter. In the author's implementation, the parameter for the double exponential moving averages is a constant, using a period value of 5. Thus, a better name for this study might be "double average channel," since it seems to be mainly a smoother way to plot a Keltner channel by double-smoothing the center line and double-smoothing the range used in determining the channel width.

A full implementation of the adaptive price zone indicator and strategy in Ensign is available as an "AdaptivePriceZone" template that Ensign users can download from Ensign's website.

--Howard Arrington
www.ensignsoftware.com
Editor's note: Lee Leibfarth's response to Ensign Software's comments.

The goal of the Apz indicator is to form a channel that quickly responds to price moves, in a fairly predictable way (thus the double weighted smoothing). I first developed the Apz for use in the intraday markets, since most band-type indicators (such as Bollinger Bands, Keltner channels, or Starc bands) form very jagged and irregular bands when set to smaller lookback lengths (around five, for instance). The bands of the Apz tend to provide a more regular response to short-term price moves.

You are correct that this indicator does not perform well in trending markets. The intent of the article is to show possible applications for this type of indicator in certain markets, but not to overstate its usefulness. The article includes a chart that illustrates an instance when a trade entry fails to work as expected. While I suggest a method of interpreting this indicator, I would hope that readers find their own unique uses as well.

The adaptive part of the indicator is that it varies the bandwidth based on market volatility (the double smoothed, exponential absolute range). While the average and the settings are not adaptive and must be tuned to individual markets or chart intervals, the bands are somewhat adaptive. In addition, the chart illustrations use custom settings and not the defaults in the code. These are as follows:

Figure 1: ES daily data (3/12/04 - 10/15/04), Period (30), BandPct (1.8)
Figure 2: QQQQ daily data (12/20/05 - 6/16/06), Period (50), BandPct (2.2)
Figure 3: YM Intraday 610-tick data (6/13/06), Period (30), BandPct (2.1)
Sidebar: ES daily data (4/4/06- 6/16/06), Period (20), BandPct (1.2), ADXTheshold (30)
         This is narrowed to provide more trades for illustrative purposes and was 
         tested on four years of historical data from major US index futures.
I do not consider this to be a fully developed system. It is a basic application of the indicator.

I appreciate your comments and insights. I want to emphasize that the intent of my writing is not to mislead or make unsubstantiated claims about the usefulness of an indicator; rather, I hope to provide ideas and research that may inform or inspire other traders in their technical analysis of the markets.
 

GO BACK

Return to September 2006 Contents

Originally published in the September 2006 issue of Technical Analysis of STOCKS & COMMODITIES magazine.
All rights reserved. © Copyright 2006, Technical Analysis, Inc.