April 2004
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: Trend-Quality Indicator
METASTOCK: Trend-Quality Indicator
CQG: Trend-Quality Indicator and Cumulative Price Change Indicator
AMIBROKER: Trend-Quality Indicator
eSIGNAL: Trend-Quality Indicator
Wealth-Lab: Trend-Quality Indicato
NEUROSHELL TRADER: Trend-Quality Indicator
AIQ TRADINGEXPERT: Trend-Quality Indicator
NeoTicker: Trend-Quality Indicator
PROPHET.NET: Trend-Quality Indicator
TechniFilter Plus: Trend-Quality Indicator
TRADE NAVIGATOR: Trend-Quality Indicator
or return to April 2004 Contents


TRADESTATION: TREND-QUALITY INDICATOR

David Sepiashvili's article in this issue, "Trend-Quality Indicator," describes a method of assessing trend strength. To accomplish this, Sepiashvili uses a summing process to determine the cumulative price change (CPC). The CPC is reset to zero at every trend reversal. Trend reversals are based on the crossing of two moving averages. The CPC is "piecewise" averaged to produce the trend, which in turn is compared to a noise calculation to produce the quality indicator.

The code given here performs these calculations. In order to match Figure 2 in Sepiashvili's article, the code plots the trend-noise balance indicator (B-indicator). To provide an indication of trend direction, a TrendPeriods indicator is included. It plots the periods variable.

 
Indicator:  TrendQuality
{ Calculating the Q-Indicator - As an example, we begin
  with a "fast" moving average length of 7 and a "slow"
  moving average length of 15 }
inputs:
 FastAvgLen( 7 ),
 SlowAvgLen( 15 ),
 M( 4 ), { % scalar trend period }
 N( 250 ), { % scalar noise period }
 Correction( 2 ) ; { % scalar correction factor }
variables:
 LPF1( 0 ),
 LPF2( 0 ),
 Reversals( 0 ),
 Periods( 0 ),
 DC( 0 ),
 CPC( 0 ),
 Trend( 0 ),
 DT( 0 ),
 Noise( 0 ),
  QIND( 0 ) ;
{ Generate reversal signals based on XAverage crossover rule }
LPF1 = XAverage( Close, FastAvgLen ) ;
LPF2 = XAverage( Close, SlowAvgLen ) ;
Reversals = LPF1 - LPF2 ;
Periods = Sign( Reversals ) ;
{ Calculate price minus previous price and compute
  cumulative sum over periods given by reversals }
DC = Close - Close[1] ;
if Periods <> Periods[1] then
 begin
 CPC = 0 ;
 Trend = 0 ;
 end
else
 begin
 CPC = CPC + DC * Periods ;
 { To calculate trend, smooth CPC by XAverage 4
   within the given segments (periods) }
 Trend = CPC * 1 / M + Trend[1] * ( 1 - ( 1 / M ) ) ;
 end ;
{ To calculate noise, subtract the trend from CPC, square it, and
   then smooth it }
DT = CPC - Trend ;
Noise = Correction * SquareRoot( Average( DT * DT, N ) ) ;
{ To calculate Q-indicator divide trend by obtained noise }
if Noise > 0 then
 QIND = Trend / Noise ;
if AbsValue( Trend ) + AbsValue( Noise ) > 0 then
 Plot1( AbsValue( Trend ) / ( AbsValue( Trend )
  + AbsValue( Noise ) ) * 100, "TrendQ" ) ;
Indicator:  TrendPeriods
inputs:
 FastAvgLen( 7 ),
 SlowAvgLen( 15 ) ;
variables:
 LPF1( 0 ),
 LPF2( 0 ),
 Reversals( 0 ),
 Periods( 0 ),
 DC( 0 ),
 CPC( 0 ) ;
LPF1 = XAverage( Close, FastAvgLen ) ;
LPF2 = XAverage( Close, SlowAvgLen ) ;
Reversals = LPF1 - LPF2 ;
Periods = Sign( Reversals ) ;
DC = Close - Close[1] ;
if Periods <> Periods[1] then
 CPC = 0
else
 CPC = CPC + DC * Periods ;
Plot2( Periods ) ;

An Eld file including this EasyLanguage strategy is available at www.tradestationworld.com. Look for the file "TrendQuality.eld." A sample chart is shown in Figure 1.

FIGURE 1:TRADESTATION, TREND-QUALITY INDICATOR. This sample TradeStation chart shows the trend-quality (Q-indicator) and trend-periods indicators on a weekly chart of Dell with seven-period and 15-period moving averages. The red line is the trend-quality indicator.
--Mark Mills
MarkM@TSSec at www.TradeStationWorld.com
EasyLanguage Questions Forum
TradeStation Securities, Inc.
A subsidiary of TradeStation Group, Inc.


GO BACK


METASTOCK: TREND-QUALITY INDICATOR

David Sepiashvili's article "Trend-Quality Indicator" introduces two new indicators: the Q-indicator and B-indicator. Both can be added to MetaStock using the formulas listed here.

To enter this indicator into MetaStock, do the following:
 

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.
Name: Q-indicator:
Formula:
m:=Input("% Scalar trend period",1,25,4);
n:=Input("% Scalar noise period",1,500,250);
cf:=Input("% Scalar correction factor",1,250,2);
p1:=Input("First moving average periods",1,200,7);
p2:=Input("Second moving average periods",1,200,15);
rev:=Mov(C,p1,E)-Mov(C,p2,E);
pds:=If(rev>0,1,-1);
dc:=ROC(C,1,$);
cpc:=If(pds<>Ref(pds,-1),0,(dc*pds)+PREV);
trend:=If(pds<>Ref(pds,-1),0,(cpc*(1/m))+(PREV*(1-(1/m))));
dt:=cpc-trend;
noise:=cf*Sqrt(Mov(dt*dt,n,S));
trend/noise
Name: B-indicator
Formula:
m:=Input("% Scalar trend period",1,25,4);
n:=Input("% Scalar noise period",1,500,250);
cf:=Input("% Scalar correction factor",1,250,2);
p1:=Input("First moving average periods",1,200,7);
p2:=Input("Second moving average periods",1,200,15);
rev:=Mov(C,p1,E)-Mov(C,p2,E);
pds:=If(rev>0,1,-1);
dc:=ROC(C,1,$);
cpc:=If(pds<>Ref(pds,-1),0,(dc*pds)+PREV);
trend:=If(pds<>Ref(pds,-1),0,(cpc*(1/m))+(PREV*(1-(1/m))));
dt:=cpc-trend;
noise:=cf*Sqrt(Mov(dt*dt,n,S));
temp:=If(Abs(trend)+Abs(noise)=0,1,Abs(trend)+Abs(noise));
(Abs(trend)/temp)*100;

William Golson
Equis Support

Figure 2 shows how these indicators look on a chart of SPY.

FIGURE 2: METASTOCK, TREND-QUALITY INDICATOR AND B-INDICATOR. Here are the Q-indicator and B-indicator on a chart of SPY.
--William Golson
Equis International
www.equis.com


GO BACK


CQG: TREND-QUALITY INDICATOR AND CUMULATIVE PRICE CHANGE INDICATOR

The Tqi_Cpc custom study has two curves, the CPC curve and the trend curve. There are three parameters: emaPeriod1, emaPeriod2, and m.

Note that the cumulative price change indicator (CPC) for uptrends is calculated separately from the CPC for downtrends, and they are then joined together at the end of the study.

For the trend curve, I calculated my own EMA of the CPC. This allowed me to restart the calculation whenever the trend switched from up to down or vice-versa. This prevents the tail end of one trend from affecting the beginning of the next trend.
 

Cumulative price change indicator (CPC)
/*
* find the number of bars since the last cross-above and
* the last cross-below
*/
crossAbove := MA(@,Exp,emaPeriod1) XAbove MA(@,Exp,emaPeriod2);
crossBelow := MA(@,Exp,emaPeriod1) XBelow MA(@,Exp,emaPeriod2);
bsXA := BarsSince( crossAbove,1,400);
bsXB := BarsSince( crossBelow,1,400);
/*
* the market is going up if the number of bars since
* the last cross-above is less than the number of bars
* since the last cross-below and vice-versa
*/
up := bsXA < bsXB;
/*
* sum all of price changes since the last cross-above
*/
delta := Close(@) - Close(@)[-1];
cpcUp := IF( crossAbove, 0, cpcUp[-1]) + delta;
cpcDown := IF( crossBelow, 0, cpcDown[-1]) + delta;
cpc := IF( up, cpcUp, cpcDown);
cpc
Trend
/*
* calculate the 4-period exponential moving average of CPC.
* re-start the calculation every time there is a cross-above or
* a cross-below.
*/
crossAbove := MA(@,Exp,emaPeriod1) XAbove MA(@,Exp,emaPeriod2);
crossBelow := MA(@,Exp,emaPeriod1) XBelow MA(@,Exp,emaPeriod2);
bsXA := BarsSince( crossAbove,1,400);
bsXB := BarsSince( crossBelow,1,400);
/*
* the market is going up if the number of bars since the last
* cross-above is less than the number of bars since the last
* cross-below
*/
up := bsXA < bsXB;
/*
* calculate the smoothing constant for exp MA period
*/
sc := IF( m > 1, 2 / ( m + 1), m);
/*
* now calculate the trend
*/
cpc := TQI_CPC.CPC^(@,emaPeriod1,emaPeriod2);
expMA := IF( crossAbove OR crossBelow, cpc, ( 1 - sc) * expMA[-1] + sc * cpc);
expMA

Trend-quality indicator The trend quality indicator has a single curve. In addition to the parameters used in the CPC indicator just given, there are two additional parameters, n and c.
 
 

Trend-quality indicator (Q-indicator)
/*
* calculate the "linear noise"
*/
dt := TQI_CPC.CPC^(@,emaPeriod1,emaPeriod2) - TQI_CPC.Trend^(@,emaPeriod1,emaPeriod2,m);
noise := c * MA(  Abs(dt),Sim,n);
/*
* now calculate the trend quality
*/
qi := TQI_CPC.Trend^(@,emaPeriod1,emaPeriod2,m) / noise;
qi
--Brian Bell, President
Custom Trading Solutions, Inc.
303 730-3388


GO BACK


AMIBROKER: TREND-QUALITY INDICATOR

In "Trend-Quality Indicator" in this issue, David Sepiashvili presents an innovative trend-detection tool -- the trend-quality indicator -- that attempts to estimate the trend in relation to noise.

Calculations presented in the article can be easily reproduced using AmiBroker Formula Language. The only tricky part is a piecewise exponential moving average that restarts the calculations on every moving average crossover, but we managed to implement it in two lines of code, thanks to AmiBroker's powerful Ama2 function, which allows easy implementation of all kinds of single-order infinite impulse response filters.

Listing 1 shows ready-to-use indicator code to plot the Q-indicator. In AmiBroker, select Indicator Builder from the Analysis menu, click the "Add" button, enter the formula, and then press "Apply." Figure 3 shows a sample chart.
 
 

FIGURE 3: AMIBROKER, TREND-QUALITY INDICATOR. This AmiBroker screenshot shows the short-term Q-indicator on Citrix Systems [CTXS] (upper pane) and a line price chart with seven- and 15-day exponential moving averages (lower pane), which reproduces the chart presented in Sepiashvili's article.
LISTING 1
// Piecewise EMA is an EMA that restarts calculations each time
// the 'sincebar' argument is true
function PiecewiseEMA( array, range, sincebar )
{
  factor = IIf( sincebar, 1, 2/(range+1) );
  return AMA2( array, factor, 1-factor );
}
// parameters
m=4;
n=250;
// generate reversal signals based on EMA crossover rule
Lpf1 = EMA( C, 7  );
Lpf2 = EMA( C, 15 );
CrossPoint = Cross( Lpf1, Lpf2 ) OR Cross( Lpf2, Lpf1 );
Periods = BarsSince( CrossPoint );
// variable bar sum
DC = Close - Ref( Close, -1 );
CPC = Sum( DC, Periods );
// smooth CPC by piecewise 4 bar EMA
Trend = PiecewiseEMA( CPC, 4, CrossPoint );
// noise
DT = CPC - Trend;
Noise = 2 * sqrt( MA( DT^2, n ) );
// alternative 'linear' noise calculation
// Noise = 2 * MA( abs( DT ), n ) );
QIndicator = Trend/Noise;
Plot(sign(Lpf1-Lpf2), "Rev", colorRed );
Plot( Qindicator, "Qindicator", colorGreen, styleHistogram);
PlotGrid( -1 );
PlotGrid( 1 );
PlotGrid( 2 );
PlotGrid( -2 );
PlotGrid( 5 );
PlotGrid( 5);
--Tomasz Janeczko, AmiBroker.com
www.amibroker.com


GO BACK


eSIGNAL: TREND-QUALITY INDICATOR

This eSignal code implements the B-indicator and Q-indicator as described in David Sepiashvili's article in this issue.
 
 

FIGURE 4: eSIGNAL, TREND-QUALITY INDICATOR. This sample eSignal chart plots David Sepiashvili's Q-indicator. Users should make sure they have enough data loaded into the chart to display this indicator properly. Users can either scroll the chart back to load more data, or set up a custom time template to load a fixed number of days, which should number at least 500.

FIGURE 5: eSIGNAL, TREND-NOISE BALANCE INDICATOR. This sample eSignal chart plots David Sepiashvili's B-indicator.
/*****************************************************************
Provided By : eSignal. (c) Copyright 2004
Study:        B-Indicator
Version:      1.0
2/10/2004
Formula Parameters:              Default:
    MA1 Periods                     10
    MA2 Periods                     40
    Scalar Trend Periods         10
    Scalar Noise Periods         52
    Scalar Correction Factor       2
    Noise Type                        Root-Mean-Squared
    CPC Smoothing                 Exponential
 
Notes:
* This version uses an EMA(7)/EMA(15) crossover study for the basis of the indicator
  calculations in the background. To view the moving averages on the price pane, they
  must be applied separately with the same inputs for length.
* It is recommended that the advanced chart uses a custom time template equal to at
  least twice the number of bars than the length specified for the Scalar Noise Periods.
*****************************************************************/
function preMain() {
    setStudyTitle("B-Indicator ");
    setCursorLabelName("B-Indicator");
 
    setDefaultBarFgColor(Color.blue, 0);
    setDefaultBarThickness(2, 0);
    setComputeOnClose();
 
  setStudyMax(115);
    setStudyMin(-5);
 
    addBand(100, PS_SOLID, 2, Color.black, "100");
    addBand(80, PS_SOLID, 2, Color.black, "80");
    addBand(65, PS_SOLID, 2, Color.black, "65");
    addBand(50, PS_SOLID, 2, Color.red, "50");
    addBand(0, PS_SOLID, 2, Color.black, "0");
 
    var fp1 = new FunctionParameter("nLen1", FunctionParameter.NUMBER);
    fp1.setName("MA1 Periods");
    fp1.setLowerLimit(1);
    fp1.setDefault(10);
    var fp2 = new FunctionParameter("nLen2", FunctionParameter.NUMBER);
    fp2.setName("MA2 Periods");
    fp2.setLowerLimit(1);
    fp2.setDefault(40);
    var fp3 = new FunctionParameter("nTrendLen", FunctionParameter.NUMBER);
    fp3.setName("Scalar Trend Periods");
    fp3.setLowerLimit(1);
    fp3.setDefault(10);
    var fp4 = new FunctionParameter("nNoiseLen", FunctionParameter.NUMBER);
    fp4.setName("Scalar Noise Periods");
    fp4.setLowerLimit(1);
    fp4.setDefault(52);
    var fp5 = new FunctionParameter("nC", FunctionParameter.NUMBER);
    fp5.setName("Scalar Correction Factor");
    fp5.setLowerLimit(0);
    fp5.setDefault(2);
 
    var fp6 = new FunctionParameter("sType", FunctionParameter.STRING);
    fp6.setName("Noise Type");
    fp6.addOption("Linear");
    fp6.addOption("Root-Mean-Squared");
    fp6.setDefault("Root-Mean-Squared");
    var fp7 = new FunctionParameter("sCPCsmoothing", FunctionParameter.STRING);
    fp7.setName("CPC Smoothing");
    fp7.addOption("Simple");
    fp7.addOption("Exponential");
    fp7.setDefault("Exponential");
}
var bEdit = true;
var MAstudy1 = null;
var MAstudy2 = null;
var nRevPeriods = 0;
var aDC = null;
var aCPC = null;
var CPC = null;
var aDT = null;
var DT = null;
var vSign = null;
// EMA variables
var vEMA = null;
var vEMA1 = null;
var dPercent = 0.0;
var bPrimed = false;
function main(nLen1, nLen2, nTrendLen, nNoiseLen, nC, sType, sCPCsmoothing) {
    var nState = getBarState();
    var i = 0;
    var vC = close();
    var vC_1 = close(-1);
    if (vC_1 == null) return;
    var DC = 0;
    var Trend = 0;
    var Noise = 1;
    var dSum = 0;
    var dSum2 = 0;
    var vQ = null;
    var vB = null;
 
    if (bEdit == true) {
        MAstudy1 = new MAStudy(Math.round(nLen1), 0, "Close", MAStudy.EXPONENTIAL);
        MAstudy2 = new MAStudy(Math.round(nLen2), 0, "Close", MAStudy.EXPONENTIAL);
        if (aDC == null) aDC = new Array(1);
        if (aCPC == null) aCPC = new Array(Math.round(nTrendLen));
        if (aDT == null) aDT = new Array(Math.round(nNoiseLen));
        bEdit = false;
    }
 
    if (nState == BARSTATE_NEWBAR) {    // crossovers
        var vEMA1 = MAstudy1.getValue(MAStudy.MA, 0);
        var vEMA2 = MAstudy2.getValue(MAStudy.MA, 0);
        var vEMA1_1 = MAstudy1.getValue(MAStudy.MA, -1);
        var vEMA2_1 = MAstudy2.getValue(MAStudy.MA, -1);
        if (vEMA1 == null || vEMA2 == null || vEMA1_1 == null || vEMA2_1 == null) return;
        if ( (vEMA1 > vEMA2 && vEMA1_1 < vEMA2_1) || (vEMA1 < vEMA2 && vEMA1_1 > vEMA2_1) ) {
            nRevPeriods = 0;
            if ( (vEMA1_1 - vEMA2_1) > 0) vSign = -1;
            if ( (vEMA1_1 - vEMA2_1) < 0) vSign = +1;
            aDC = new Array(1);
            aCPC = new Array(Math.round(nTrendLen));
            CPC = null;
            bPrimed = false;
        } else {
            nRevPeriods += 1;
        }
        if (CPC != null) {
            aCPC.pop();
            aCPC.unshift(CPC);
        }
        if (DT != null) {
            aDT.pop();
            aDT.unshift(DT);
        }
    }
 
    // DC
    DC = (vC - vC_1);
    aDC[nRevPeriods] = DC;
    // CPC
    CPC = 0;
    for(i = 0; i < nRevPeriods+1; ++i) {
        CPC += aDC[i];
    }
    aCPC[0] = CPC
 
    // Trend
    if (nRevPeriods > 0) {
        if (sCPCsmoothing == "Exponential") {
            if (aCPC[nTrendLen-1] != null) {
                vEMA = EMA(nTrendLen, aCPC);
                Trend = vEMA;
            } else {
                for (i = 0; i < nRevPeriods+1; ++i) {
                    dSum2 += aCPC[i];
                }
                Trend = (dSum2/(nRevPeriods+1));
            }
        } else if (sCPCsmoothing == "Simple") {
            i = 0;
            for (i = 0; i < Math.min((nRevPeriods+1),nTrendLen); ++i) {
                dSum2 += aCPC[i];
            }
            Trend = (dSum2/Math.min((nRevPeriods+1),nTrendLen));
        }
    }
 
    // Noise
    if (sType == "Root-Mean-Squared") {
        DT = (CPC - Trend)*(CPC - Trend);
        aDT[0] = DT;
        if (aDT[nNoiseLen-1] != null) {
            i = 0;
            for (i = 0; i < nNoiseLen; ++i) {
                dSum += aDT[i];
            }
            dSum /= nNoiseLen;
            Noise = Math.sqrt(dSum) * nC;
        }
    } else if (sType == "Linear") {
        DT = Math.abs(CPC - Trend);
        aDT[0] = DT;
        if (aDT[nNoiseLen-1] != null) {
            i = 0;
            for (i = 0; i < nNoiseLen; ++i) {
                dSum += aDT[i];
            }
            dSum /= nNoiseLen;
            Noise = dSum * nC;
        }
    }
 
    // B-Indicator
    vB = (Math.abs(Trend) / (Math.abs(Trend)+Noise)) * 100;
    if (isNaN(vB)) vB = 100;
    return vB;
}
/***************
    Functions
****************/
function EMA(nLength, nArray) {
    var nBarState = getBarState();
    var dSum = 0.0;
    var dRef;
    if(nBarState == BARSTATE_ALLBARS || bPrimed == false) {
        dPercent = (2.0 / (nLength + 1.0));
        bPrimed = false;
    }
    if (nBarState == BARSTATE_NEWBAR) {
        vEMA1 = vEMA;
    }
    if(bPrimed == false) {
        for(i = 0; i < nLength; i++) {
            dSum += nArray[i];
        }
        bPrimed = true;
        return (dSum / nLength);
    } else {
        return (((CPC - vEMA1) * dPercent) + vEMA1);
    }
}
/*****************************************************************
Provided By : eSignal. (c) Copyright 2004
Study:        Q-Indicator
Version:      1.0
2/10/2004
Formula Parameters:                 Default:
    MA1 Periods                     7
    MA2 Periods                     15
    Scalar Trend Periods            4
    Scalar Noise Periods            250
    Scalar Correction Factor        2
    Noise Type                      Root-Mean-Squared
    CPC Smoothing                   Exponential
 
Notes:
    * This version uses an EMA(7)/EMA(15) crossover study for the
      basis of the indicator calculations in the background.  To
      view the moving averages on the price pane, they must be
      applied separately with the same inputs for length.
    * It is recommended that the advanced chart uses a custom time
      template equal to at least twice the number of bars than the
      length specified for the Scalar Noise Periods of 250.
*****************************************************************/
function preMain() {
    setStudyTitle("Q-Indicator ");
    setCursorLabelName("Reversal Sign", 0);
    setCursorLabelName("Q-Indicator", 1);
    setComputeOnClose();
 
    setPlotType(PLOTTYPE_HISTOGRAM, 1);
    setDefaultBarFgColor(Color.red, 0);
    setDefaultBarFgColor(Color.navy, 1);
    setDefaultBarThickness(2, 0);
    setDefaultBarThickness(3, 1);
 
    addBand(5, PS_SOLID, 2, Color.black, "+5");
    addBand(2, PS_SOLID, 2, Color.black, "+2");
    addBand(1, PS_SOLID, 2, Color.maroon, "+1");
    addBand(-1, PS_SOLID, 2, Color.maroon, "-1");
    addBand(-2, PS_SOLID, 2, Color.black, "-2");
    addBand(-5, PS_SOLID, 2, Color.black, "-5");
 
    var fp1 = new FunctionParameter("nLen1", FunctionParameter.NUMBER);
    fp1.setName("MA1 Periods");
    fp1.setLowerLimit(1);
    fp1.setDefault(7);
    var fp2 = new FunctionParameter("nLen2", FunctionParameter.NUMBER);
    fp2.setName("MA2 Periods");
    fp2.setLowerLimit(1);
    fp2.setDefault(15);
    var fp3 = new FunctionParameter("nTrendLen", FunctionParameter.NUMBER);
    fp3.setName("Scalar Trend Periods");
    fp3.setLowerLimit(1);
    fp3.setDefault(4);
    var fp4 = new FunctionParameter("nNoiseLen", FunctionParameter.NUMBER);
    fp4.setName("Scalar Noise Periods");
    fp4.setLowerLimit(1);
    fp4.setDefault(250);
    var fp5 = new FunctionParameter("nC", FunctionParameter.NUMBER);
    fp5.setName("Scalar Correction Factor");
    fp5.setLowerLimit(0);
    fp5.setDefault(2);
 
    var fp6 = new FunctionParameter("sType", FunctionParameter.STRING);
    fp6.setName("Noise Type");
    fp6.addOption("Linear");
    fp6.addOption("Root-Mean-Squared");
    fp6.setDefault("Root-Mean-Squared");
    var fp7 = new FunctionParameter("sCPCsmoothing", FunctionParameter.STRING);
    fp7.setName("CPC Smoothing");
    fp7.addOption("Simple");
    fp7.addOption("Exponential");
    fp7.setDefault("Exponential");
}
var bEdit = true;
var MAstudy1 = null;
var MAstudy2 = null;
var nRevPeriods = 0;
var aDC = null;
var aCPC = null;
var CPC = null;
var aDT = null;
var DT = null;
var vSign = null;
// EMA variables
var vEMA = null;
var vEMA1 = null;
var dPercent = 0.0;
var bPrimed = false;
function main(nLen1, nLen2, nTrendLen, nNoiseLen, nC, sType, sCPCsmoothing) {
    var nState = getBarState();
    var i = 0;
    var vC = close();
    var vC_1 = close(-1);
    if (vC_1 == null) return;
    var DC = 0;
    var Trend = 0;
    var Noise = 1;
    var dSum = 0;
    var dSum2 = 0;
    var vQ = null;
 
    if (bEdit == true) {
        MAstudy1 = new MAStudy(Math.round(nLen1), 0, "Close", MAStudy.EXPONENTIAL);
        MAstudy2 = new MAStudy(Math.round(nLen2), 0, "Close", MAStudy.EXPONENTIAL);
        if (aDC == null) aDC = new Array(1);
        if (aCPC == null) aCPC = new Array(Math.round(nTrendLen));
        if (aDT == null) aDT = new Array(Math.round(nNoiseLen));
        bEdit = false;
    }
 
    if (nState == BARSTATE_NEWBAR) {    // crossovers
        var vEMA1 = MAstudy1.getValue(MAStudy.MA, 0);
        var vEMA2 = MAstudy2.getValue(MAStudy.MA, 0);
        var vEMA1_1 = MAstudy1.getValue(MAStudy.MA, -1);
        var vEMA2_1 = MAstudy2.getValue(MAStudy.MA, -1);
        if (vEMA1 == null || vEMA2 == null || vEMA1_1 == null || vEMA2_1 == null) return;
        if ( (vEMA1 > vEMA2 && vEMA1_1 < vEMA2_1) || (vEMA1 < vEMA2 && vEMA1_1 > vEMA2_1) ) {
            nRevPeriods = 0;
            if ( (vEMA1_1 - vEMA2_1) > 0) vSign = -1;
            if ( (vEMA1_1 - vEMA2_1) < 0) vSign = +1;
            aDC = new Array(1);
            aCPC = new Array(Math.round(nTrendLen));
            CPC = null;
            bPrimed = false;
        } else {
            nRevPeriods += 1;
        }
        if (CPC != null) {
            aCPC.pop();
            aCPC.unshift(CPC);
        }
        if (DT != null) {
            aDT.pop();
            aDT.unshift(DT);
        }
    }
 
    // DC
    DC = (vC - vC_1);
    aDC[nRevPeriods] = DC;
    // CPC
    CPC = 0;
    for(i = 0; i < nRevPeriods+1; ++i) {
        CPC += aDC[i];
    }
    aCPC[0] = CPC
 
    // Trend
    if (nRevPeriods > 0) {
        if (sCPCsmoothing == "Exponential") {
            if (aCPC[nTrendLen-1] != null) {
                vEMA = EMA(nTrendLen, aCPC);
                Trend = vEMA;
            } else {
                i = 0;
                for (i = 0; i < nRevPeriods+1; ++i) {
                    dSum2 += aCPC[i];
                }
                Trend = (dSum2/(nRevPeriods+1));
            }
        } else if (sCPCsmoothing == "Simple") {
            i = 0;
            for (i = 0; i < Math.min((nRevPeriods+1),nTrendLen); ++i) {
                dSum2 += aCPC[i];
            }
            Trend = (dSum2/Math.min((nRevPeriods+1),nTrendLen));
        }
    }
 
    // Noise
    if (sType == "Root-Mean-Squared") {
        DT = (CPC - Trend)*(CPC - Trend);
        aDT[0] = DT;
        if (aDT[nNoiseLen-1] != null) {
            i = 0;
            for (i = 0; i < nNoiseLen; ++i) {
                dSum += aDT[i];
            }
            dSum /= nNoiseLen;
            Noise = Math.sqrt(dSum) * nC;
        }
    } else if (sType == "Linear") {
        DT = Math.abs(CPC - Trend);
        aDT[0] = DT;
        if (aDT[nNoiseLen-1] != null) {
            i = 0;
            for (i = 0; i < nNoiseLen; ++i) {
                dSum += aDT[i];
            }
            dSum /= nNoiseLen;
            Noise = dSum * nC;
        }
    }
 
    // Q-Indicator
    if (Noise != 0) {
        vQ = (Trend/Noise);
    }
 
    return new Array(vSign, vQ);
}
/***************
    Functions
****************/
function EMA(nLength, nArray) {
    var nBarState = getBarState();
    var dSum = 0.0;
    var dRef;
    if(nBarState == BARSTATE_ALLBARS || bPrimed == false) {
        dPercent = (2.0 / (nLength + 1.0));
        bPrimed = false;
    }
    if (nBarState == BARSTATE_NEWBAR) {
        vEMA1 = vEMA;
    }
    if(bPrimed == false) {
        for(i = 0; i < nLength; i++) {
            dSum += nArray[i];
        }
        bPrimed = true;
        return (dSum / nLength);
    } else {
        return (((CPC - vEMA1) * dPercent) + vEMA1);
    }
}


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


GO BACK


WEALTH-LAB: TREND-QUALITY INDICATOR

The trend-quality indicator (Q-indicator) and trend-noise balance indicator (B-indicator) described by David Sepiashvili in his article, "Trend-Quality Indicator," have been added to the Wealth-Lab code library and are available for download by selecting Community|Download ChartScripts from Wealth-Lab Developer's main menu. Website users also can employ both indicators in their ChartScripts by making the $Include references as given in the code shown in this tip.

The Trend Q, B system demonstrates how you can use the Q and B indicators to both join and exit a trend. As suggested by Sepiashvili, we constrain the trade entry to the conditions Q > 1 AND B > 50. While the system will exit a trade if B indicates the end of the trend by dropping to zero, we also include a trailing stop at the 100-period simple moving average. Following an exit, the system is inhibited from rejoining the same trend (Figure 6).

FIGURE 6: WEALTH-LAB, TREND-QUALITY INDICATORS. The Trend Q, B demo system uses the indicators to enter and exit the market.

Note that the Q and B scalar parameters, whose values are rather arbitrary here, can be tweaked or optimized to improve performance.
 

{$I 'TrendB'}
{$I 'TrendQ'}
var Bar, TB, TQ, p, TBPane, TQPane, hMA: integer;
var EntryInhibit, TBExit: boolean;
hMA := SMASeries( #Close, 100 );
TB := TrendBSeries( #Close, 10, 40, 8, 250, 4, true );
TQ := TrendQSeries( #Close, 10, 40, 8, 250, 4, true );
{ --------
 Plot routine }
PlotStops;
HideVolume;
TBPane := CreatePane( 125, false, true );
TQPane := CreatePane( 125, false, true );
PlotSeriesLabel( TB, TBPane, #Teal, #Thick, 'TrendB' );
PlotSeriesLabel( TQ, TQPane, #Navy, #Histogram, 'TrendQ' );
DrawHorzLine( 50, TBPane, #Red, #Dotted );
DrawHorzLine( 65, TBPane, #Black, #Dotted );
DrawHorzLine( 80, TBPane, #Blue, #Dotted );
{ --------
 Demo system }
for Bar := 250 to BarCount - 1 do
begin
  if ( @TB[Bar] > 50 ) and ( @TQ[Bar] > 0 ) then
    SetPaneBackgroundColor( Bar, TBPane, #BlueBkg );
  if @TQ[Bar] > 1 then
    SetSeriesBarColor( Bar, TQ, #Green )
  else if @TQ[Bar] < -1 then
    SetSeriesBarColor( Bar, TQ, #Red );
  TBExit := false;
  if CrossUnderValue( Bar, TB, 0.1 ) then
  begin
    EntryInhibit := false;
    TBExit := true;
  end;
  if not LastPositionActive then
  begin   { Entry Rules }
    if not EntryInhibit then
      if ( @TQ[Bar] > 1 ) and ( @TB[Bar] > 50 )then
      begin
        EntryInhibit := true;
        BuyAtMarket( Bar + 1, '' );
      end;
  end
  else
  begin  { Exit Rules }
    p := LastPosition;
    if not SellAtStop( Bar + 1, @hMA[Bar], p, 'TStp' ) then
      if TBExit then
        SellAtMarket( Bar + 1, p, 'TB_Exit' );
  end;
end;
-- Robert Sucher, Wealth-Lab, Inc.
www.wealth-lab.com


GO BACK



 

NEUROSHELL TRADER: TREND-QUALITY INDICATOR

The trend-quality indicators described by David Sepiashvili can be easily implemented in NeuroShell Trader by combining a few of NeuroShell Trader's 800 indicators and two custom indicators. To implement the Q-indicator and B-indicator, select "New Indicator ..." from the Insert menu and use the Indicator Wizard to create the following indicators:
 

REVERSAL:
    OR2 ( ExpCrossAbove(Close,7,15), ExpCrossBelow(Close,7,15) )
CPC:
    PiecewiseCumulativeChange ( Close, REVERSAL )
TREND:
    PiecewiseExpAvg ( CPC, REVERSAL, 4 )
DT:
    Sub ( CPC, TREND )
NOISE:
    Mult2 ( 2, Sqrt ( MovAvg ( Mult2 ( DT, DT ), 250 ) ) )
QINDICATOR:
    Divide ( TREND, NOISE )
BINDICATOR:
    Divide ( AbsoluteValue ( TREND ), Add2 ( AbsoluteValue ( TREND ), NOISE ) )


Note that the PiecewiseCumulativeChange and PiecewiseExpAvg indicators are custom indicators.

Users of NeuroShell Trader can go to the Stocks & Commodities section of the NeuroShell Trader free technical support website to download the piecewise custom indicators as well as a sample chart that includes the trend-quality indicators.

A sample chart is shown in Figure 7.

FIGURE 7: NEUROSHELL TRADER, TREND-QUALITY INDICATORS. This sample chart in NeuroShell Trader shows the Q-indicator (middle pane) and the B-indicator (bottom pane) on Citrix Systems [CTXS].

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


GO BACK


AIQ TRADINGEXPERT: TREND-QUALITY INDICATOR

Here is the code for AIQ TradingExpert, based on David Sepiashvili's article this issue.
 

!TREND QUALITY INDICATOR  by David Sepiahvilli (TASC Mar 2004)
!Coded by Rich Denning 2/09/04
m is 4.
n is 250.
c is 2.
LPF1 is expavg([close],7).
LPF2 is expavg([close],15).
Diff is LPF1 - LPF2.
Reversal if Diff > 0 and valresult(Diff,1) <= 0.
HD is Hasdatafor(2000).
Periods is scanany(Reversal, HD,0) then offsettodate(month(),day(),year()).
Date is scanany(Reversal, HD,0).
DC is [close] - val([close],1).
CPC is simpleavg(DC,^Periods,0) * ^Periods.
Trend is expavg(CPC,min(m,^Periods)).
DT is CPC - TREND.
NOISE is c * simpleavg(abs(DT),n).
QIND is TREND / NOISE.


--Rich Denning
AIQ Systems

GO BACK


NEOTICKER: TREND-QUALITY INDICATOR

The two indicators presented in "Trend-Quality Indicator" by David Sepiashvili, Q-indicator and B-indicator, can be implemented in NeoTicker using formula language.

Q-indicator

The NeoTicker formula language for the Q-indicator (Listing 1) has five parameters: period 1, period 2, m, n and c, in accordance to the code given in the article. Period 1 and Period 2 are the values used for generating the exponential moving average crossover rule, Periods. The Q-indicator is plotted as a histogram in a new pane.

To reproduce the chart shown in the article in NeoTicker, load CTXS daily data into a new chart. Add the Q-indicator to the data series (Figure 8).

FIGURE 8: NEOTICKER, TREND-QUALITY INDICATOR. Here's a sample chart in NeoTicker.

B-indicator

The NeoTicker formula language for the B-indicator (Listing 2) also has five parameters: period 1, period 2, m, n, and c. These parameters are used to generate the trend and noise values. The B-indicator is plotted as a line in the new pane (Figure 9).

FIGURE 9: NEOTICKER, TREND-NOISE BALANCE INDICATOR. Here's the B-indicator as plotted in NeoTicker.
LISTING 1
LPF1 := qc_xaverage(c, param1);
LPF2 := qc_xaverage(c, param2);
REVERSAL := LPF1-LPF2;
PeriodA := if((REVERSAL > 0) and (REVERSAL(1) <= 0), 0, PeriodA+1);
PeriodB := if((REVERSAL < 0) and (REVERSAL(1) >= 0), 0, PeriodB+1);
PERIODS := if(REVERSAL > 0, PeriodA, PeriodB);
DC := c-c(1);
CPC := varsum(DC,PERIODS);
TREND := qc_xaverage(CPC, param3);
myDT := CPC - TREND;
myDT_abs := absvalue(myDT);
NOISE := param5*average(myDT_abs, param4);
plot1 := TREND/NOISE;
LISTING 2
LPF1 := qc_xaverage(c, param1);
LPF2 := qc_xaverage(c, param2);
REVERSAL := LPF1-LPF2;
PeriodA := if((REVERSAL > 0) and (REVERSAL(1) <= 0), 0, PeriodA+1);
PeriodB := if((REVERSAL < 0) and (REVERSAL(1) >= 0), 0, PeriodB+1);
PERIODS := if(REVERSAL > 0, PeriodA, PeriodB);
DC := c-c(1);
CPC := varsum(DC,PERIODS);
TREND := qc_xaverage(CPC, param3);
myDT := CPC - TREND;
myDT_abs := absvalue(myDT);
NOISE := param5*average(myDT_abs, param4);
plot1 := if((absvalue(TREND)+absvalue(NOISE)) > 0,
         absvalue(TREND)/(absvalue(TREND)+absvalue(NOISE))*100, 0);
success1 := if((absvalue(TREND)+absvalue(NOISE)) > 0, 1, 0);
A downloadable version of the indicators will be available from the Yahoo! NeoTicker user group file area at https://groups.yahoo.com/group/neoticker/.
--Kenneth Yuen, TickQuest Inc.
www.tickquest.com


GO BACK



 

PROPHET.NET: TREND-QUALITY INDICATOR

The two indicators, trend-quality and trend-noise balance, described by David Sepiashvili in his article in this issue, are available on the Prophet.Net website to all premium members. No coding is required on the part of the user.

The trend-quality indicator (Q-indicator) shows the direction and strength of a trend. The trend-noise balance indicator (B-indicator), also shows the trend, but indicates overbought and oversold conditions as well. For one-click access to these indicators, go to JavaCharts from your computer's browser:

  Prophet.Net : Analyze : JavaCharts
  https://www.prophet.net/analyze/javacharts.jsp

Click on the Tools menu (which you can also access by right-clicking anywhere on a chart) and choose "Apply studies" from the Studies menu item. The list of available studies (approximately 150 of them, shown in alphabetical order) are in the second dropdown menu; you can choose trend-quality and trend-noise balance from this list. You may also adjust the parameters for either of these studies if you desire.

Figure 10 shows an example of the QQQ chart over a nine-month period with both of these indicators applied. Note that with the Q-indicator, red horizontal lines are provided to show the significant values cited in the article (-5, -2, +2, and +5) to determine trend strength.

FIGURE 10: PROPHET.NET, TREND-QUALITY INDICATORS. Here's a sample QQQ chart with the Q-indicator and B-indicator plotted. Note that with the Q-indicator, red horizontal lines show the significant values with which to determine trend strength.

Premium memberships at Prophet.Net start at $14.95 per month; real-time market data is available for equities, options, and futures. The following link will provide immediate access to all premium studies: https://www.prophet.net/tasc

--Prophet.net
GO BACK


 

TECHNIFILTER PLUS: TREND-QUALITY INDICATOR

Here are the formulas and a filter report for TechniFilter Plus based on the trend-quality indicator (Figure 11) and B-indicator (Figure 12) discussed in David Sepiashvili's article in this issue. To use different time periods, simply change the parameter as required.

FIGURE 11: TECHNIFILTER PLUS, TREND-QUALITY INDICATOR. Here's a sample chart of the Q-indicator in TechniFilter Plus.

FIGURE 12: TECHNIFILTER PLUS, TREND-NOISE BALANCE INDICATOR. Here's a sample chart of the B-indicator in TechniFilter Plus.
Formulas
NAME: CPC
SWITCHES: multiline
PARAMETERS: 7,15,4,0.5,250
FORMULA:
[1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+((1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
[2]: C-Cy1  {DC}
[3]: [2]F[1]{CPC}
NAME: Q-Indicator
SWITCHES: multiline
PARAMETERS: 7,15,4,0.5,250
FORMULA:
[1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+((1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
[2]: C-Cy1  {DC}
[3]: [2]F[1]{CPC}
[4]: ([3]x&3)x[1] {Trend}
[5]: [3]-[4] {DT}
[6]: ([5]u0X&5)* &4{Noise}
[7]: [4]/[6]{c}{NQ-Ind}{nc}{a}{h}  {rgb#255}
NAME: B-Indicator
SWITCHES: multiline
PARAMETERS: 7,15,4,0.5,250
FORMULA:
[1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+((1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
[2]: C-Cy1  {DC}
[3]: [2]F[1]{CPC}
[4]: (([3]x&3)x[1])u0{Trend}
[5]: [3]-[4] {DT}
[6]: (([5]u0X&5)* &4)u0{Noise}
[7]: ([4]/([4]+[6]))*100{c}{NB-Ind}{nc}{a}  {rgb#16711680}
Trend-quality indicator filter /screening report

The following filter report (see sample in Figure 13) can be used to scan a database and then filter out those issues that meet the required Q-indicator or B-indicator limits.

FIGURE 13: TECHNIFILTER PLUS, FILTER COMPUTED Report.  Note the latest values for the Q-Indicator and B-Indicator.
NAME: Trend Quality Indicator
UNITS TO READ: 750
FORMULAS
--------

  [1] Symbol
  [2] CPC(7,15,4,0.5,250)
   [1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+
   (1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
   [2]: C-Cy1  {DC}
   [3]: [2]F[1]{CPC}
[3] Q-Indicator(7,15,4,0.5,250)
   [1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+
   ((1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
   [2]: C-Cy1  {DC}
   [3]: [2]F[1]{CPC}
   [4]: ([3]x&3)x[1] {Trend}
   [5]: [3]-[4] {DT}
   [6]: ([5]u0X&5)* &4{Noise}
   [7]: [4]/[6]
[4] B-Indicator(7,15,4,0.5,250)
   [1]: ((((cx&1-cx&2)u2)=1)*((((cx&1-cx&2)u2)=1)U7))+
   ((1-(((cx&1-cx&2)u2)=1))*((((cx&1-cx&2)u3)=-1)U7)) {Periods}
   [2]: C-Cy1  {DC}
   [3]: [2]F[1]{CPC}
   [4]: (([3]x&3)x[1])u0{Trend}
   [5]: [3]-[4] {DT}
   [6]: (([5]u0X&5)* &4)u0{Noise}
   [7]: ([4]/([4]+[6]))*100
FILTERS--------

[1] Q_Weak Trending UP
[3] >= 1  & [3] <= 2
[2] Q_moderate Trending UP
[3] >= 2  & [3] <= 5
[3] Q_Strong Trending UP
[3] > 5
[4] Q_Weak TrendingDown
[3] <= -1  & [3] >= -2
[5] Q_Moderate TrendingDown
[3] <= -2  & [3] >= -5
[6] Q_Strong Trending Down
[3] <- 5
[7] B_Weak Trending UP
[4] >= 50  & [3] <= 65
[8] B_Moderate Trending UP
[4] >65  & [3] <= 80
[9] B_Strong Trending UP
[4] >80


Visit the new home of TechniFilter Plus at www.technifilter.com to download these reports and formulas.
 

--Benzie Pikoos
Brightspark
Tel +61 8 9375-1178, sales@technifilter.com
www.technifilter.com


GO BACK



 

TRADE NAVIGATOR: TREND-QUALITY INDICATOR

David Sepiashvili's article "Trend-Quality Indicator" examines trend detection and strength in a new way by introducing the trend-quality indicator (Figure 14).

FIGURE 14: TRADE NAVIGATOR, Q-INDICATOR. This sample Trade Navigator chart shows the Q-indicator along with the reversal indicator on an IBM daily chart.

Here is the TradeSense code for five indicators: reversal, cumulative price change (CPC), trend, noise, and the Q-indicator. The formulas are intended for use within the Trade Navigator Gold and Platinum versions, but we could also provide a special file for Trade Navigator Silver users.

To enter each of these indicators into Trade Navigator, first pull up your Traders Toolbox. Continue to the Functions tab, and click on New. You will now have a New Function window (Figure 15) where you will enter the formula for the reversal function.

FIGURE 15: TRADE NAVIGATOR, Q-INDICATOR. Enter the formula for the reversal function in the New Function window. To create the next function, go back to the toolbox by clicking the Toolbox button.

In order to calculate CPC trend, noise and Q-indicator, you must first create the reversal function. The reversal function uses an exponential moving average crossover rule to generate starting points for the CPC indicator. Once you finish typing in the formula, click on Save, and name it appropriately. To create the next function, go back to the toolbox by clicking the Toolbox button (Figure 15), and click the New button on the Functions tab. Each of these indicators, once created, can be added to the charts by clicking the letter "A" on the keyboard, selecting the Indicators tab, and then double-clicking on the name of the desired indicator.

Note: Each indicator has inputs that need to be defined on the Inputs tab of the Function editor (please see the default values for inputs under each formula).
 

Reversal
Formula:
Sign (MovingAvgX (Close , XMA1) - MovingAvgX (Close , XMA2))
Default values for inputs:
XMA1 = 7
XMA2 = 15
CPC
Formula:
CumulativeSum (Close - Close.1 , 0) - CumulativeSum (Close - Close.1 , 0)
Bars Since (Reversal (XMA1 , XMA2) <> Reversal (XMA1 , XMA2).1 , 1 , 0)
Default values for inputs:
XMA1 = 7
XMA2 = 15
Trend
Formula:
MovingAvgX (CPC (XMA1 , XMA2) , TrendPeriod)
Default values for inputs:
XMA1 = 7
XMA2 = 15
TrendPeriod = 4
Noise
Formula:
CorrFactor * SqrRoot (MovingAvg ((CPC (XMA1 , XMA2) - Trend (XMA1 , XMA2 ,
 TrendPeriod)) * (CPC (XMA1 , XMA2) - Trend (XMA1 , XMA2 , TrendPeriod)) ,
 NoisePeriod))
Default values for inputs:
CorrFactor = 2
XMA1 = 7
XMA2 = 15
TrendPeriod = 4
NoisePeriod = 250
QIndicator
Formula:
Trend (XMA1 , XMA2 , TrendPeriod) / Noise (NoisePeriod , CorrFactor , XMA1 ,
 XMA2 , TrendPeriod)
Default values for inputs:
NoisePeriod = 250
CorrFactor = 2
XMA1 = 7
XMA2 = 15
TrendPeriod = 4


 For more information on Trade Navigator, please visit www.GenesisFT.com.

--Chad Noble
GFT Strategic Development
Genesis Financial Technologies, Inc.
CNoble@GFDS.com
719 884-0245, Support@GFDS.com


GO BACK


All rights reserved. © Copyright 2004, Technical Analysis, Inc.


Return to April 2004 Contents