January 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: SWISS ARMY KNIFE INDICATOR (SWAK)
WEALTH-LAB: CHIRPED SINE WAVE
AMIBROKER: SWISS ARMY KNIFE INDICATOR (SWAK)
eSIGNAL: SWISS ARMY KNIFE INDICATOR (SWAK)
NEUROSHELL TRADER: SWISS ARMY KNIFE INDICATOR (SWAK)
NEOTICKER: SWISS ARMY KNIFE INDICATOR (SWAK)
TRADING SOLUTIONS: SWISS ARMY KNIFE INDICATOR (SWAK)
FINANCIAL DATA CALCULATOR: SWISS ARMY KNIFE INDICATOR (SWAK)
VT Trader: SWISS ARMY KNIFE INDICATOR (SWAK)
TRADECISION: SWISS ARMY KNIFE INDICATOR (SWAK)

or return to January 2006 Contents



TRADESTATION: SWISS ARMY KNIFE INDICATOR (SWAK)

John Ehlers' article in this issue, "Swiss Army Knife Indicator," presents a generalized filtering algorithm capable of creating simple averages, exponential averages, and momentum measurements. Late in the article, Ehlers suggests creating an MACD-style indicator from two-band pass filters. The following EasyLanguage code performs this task by converting the EasyLanguage code published in the article into a function called "SwakofFilters." The function is then called from two indicators: "Swak_2Lines," which plots two filtered price series, and "Swak_Diff," which plots the filtered difference between two filtered price series. Finally, here is a strategy that trades like an MACD strategy would, except that it uses the crossing of SWAK lines to generate trades.


FIGURE 1: TRADESTATION, SWISS ARMY KNIFE INDICATOR. The subgraph 1 at the top of the chart shows CISCO daily line-on-close bars. The trades shown are generated by the strategy "SWAK_ConvDiv." Directly beneath the price bars is the "SWAK_Diff" indicator (in subgraph 2). Subgraph 3 shows the filtered price series calculated by the indicator "SWAK_2Lines."


To download this code, search for the file "Swak.eld" at the TradeStation Support Center at www.TradeStation.com. Search for the file in the "TradeStation and EasyLanguage Support" discussion forum. The original code by John Ehlers is included in the ELD file as the indicator "EhlersSwak."

Function Name: Swiss Army Knife Indicator
Short Name: SWAK
Inputs: Price, c0, c1, N, b0, b1, b2, a1, a2, Initial Value
If (GT (Bar# (), N), Add (Mult (c0, Add (Mult (b0, Price), Add (Mult (b1, Lag (Price, 1)),
 Mult (b2, Lag (Price, 2))))), Add (Mult (a1, Prev (1)), Sub (Mult (a2, Prev (2)), Mult
 (c1, Lag (Price, N))))), Initial Value)
Function Name: SWAK Alpha for One-Pole Filter
Short Name: SWAK_OnePoleAlpha
Inputs: Period
Div (Add (Cos (DtoR (Div (360,Period))),Sub (Sin (DtoR (Div (360,Period))),1)),Cos (DtoR
 (Div (360,Period))))

Function Name: SWAK Exponential Moving Average
Short Name: SWAK_EMA
Inputs: Price, Period
SWAK (Price,1,0,0,SWAK_OnePoleAlpha (Period),0,0,Sub (1,SWAK_OnePoleAlpha (Period)),0,Price)

Function Name: SWAK Simple Moving Average
Short Name: SWAK_SMA
Inputs: Price, Period
SWAK (Price,1,Div (1,Period),Period,Div (1,Period),0,0,1,0,Price)

Function Name: SWAK Beta for Two-Pole Filter
Short Name: SWAK_TwoPoleBeta
Inputs: Period
Mult (2.415, Sub (1, Cos (DtoR (Div (360, Period)))))

Function Name: SWAK Alpha for Two-Pole Filter
Short Name: SWAK_TwoPoleAlpha
Inputs: Period
Sub (Sqrt (Add (Pow (SWAK_TwoPoleBeta (Period),2),Mult (2,SWAK_TwoPoleBeta (Period)))),
 SWAK_TwoPoleBeta (Period))

Function Name: SWAK Two-Pole Gaussian Filter
Short Name: SWAK_Gauss
Inputs: Price, Period
SWAK (Price,Pow (SWAK_TwoPoleAlpha (Period),2),0,0,1,0,0,Mult (2,Sub (1,SWAK_TwoPoleAlpha
 (Period))),Negate (Pow (Sub (1,SWAK_TwoPoleAlpha (Period)),2)),Price)

Function Name: SWAK Two-Pole Butterworth Filter
Short Name: SWAK_Butter
Inputs: Price, Period
SWAK (Price,Div (Pow (SWAK_TwoPoleAlpha (Period),2),4),0,0,1,2,1,0,0,Price)

Function Name: SWAK High-Pass Filter
Short Name: SWAK_HP
Inputs: Price, Period
SWAK (Price,Sub (1,SWAK_OnePoleAlpha (Period)),0,0,1,-1,0,Sub (1,SWAK_OnePoleAlpha (Period)),0,0)

Function Name: SWAK Two-Pole High-Pass Filter
Short Name: SWAK_2PHP
Inputs: Price, Period
SWAK (Price,Pow (Sub (1,Div (SWAK_TwoPoleAlpha (Period),2)),2),0,0,1,-2,1,Mult (2,Sub (1,
 SWAK_TwoPoleAlpha (Period))),Negate (Pow (Sub (1,SWAK_TwoPoleAlpha (Period)),2)),0)

Function Name: SWAK Beta for Bandpass Filter
Short Name: SWAK_BandpassBeta
Inputs: Period
Cos (DtoR (Div (360,Period)))

Function Name: SWAK Gamma for Bandpass Filter
Short Name: SWAK_BandpassGamma
Inputs: Period, delta
Div (1,Cos (DtoR (Div (Mult (720,delta),Period)))

Function Name: SWAK Alpha for Bandpass Filter
Short Name: SWAK_BandpassAlpha
Inputs: Period, delta
Sub (SWAK_BandpassGamma (Period,delta),Sqrt (Sub (Pow (SWAK_BandpassGamma (Period,delta),2),1)))

Function Name: SWAK Bandpass Filter
Short Name: SWAK_BP
Inputs: Price, Period, delta
SWAK (Price,Div (Sub (1,SWAK_BandpassAlpha (Period,delta)),2),0,0,1,0,-1,Mult (SWAK_BandpassBeta
 (Period), Add (1,SWAK_BandpassAlpha (Period,delta))), Negate (SWAK_BandpassAlpha (Period, delta)),
 Price)

Function Name: SWAK Band_Stop Filter
Short Name: SWAK_BS
Inputs: Price, Period, delta
SWAK (Price,Div (Sub (1,SWAK_BandpassAlpha (Period,delta)),2),0,0,1,Mult (-2,SWAK_BandpassBeta
 (Period)),1,Mult (SWAK_BandpassBeta (Period),Add (1,SWAK_BandpassAlpha (Period,delta))), Negate
 (SWAK_BandpassAlpha (Period,delta)),Price)

--Mark Mills
TradeStation Securities, Inc.
A subsidiary of TradeStation Group, Inc.
www.TradeStationWorld.com
GO BACK

WEALTH-LAB: CHIRPED SINE WAVE

We'll keep our Traders' Tip simple this month and recreate the chirped sine wave so that you too can easily visualize your filters on a theoretical periodic signal. You'll find the SWAK indicator in the Wealth-Lab Code Library, ready to use in the battle between the bulls and the bears!

See Figure 2 for an example.


FIGURE 2: WEALTH-LAB, CHIRPED SINE WAVE. Here's a sample implementation of the chirped sine wave in Wealth-Lab.
WealthScript code:
{$I 'SWAK'}
var Bar, CSW, CSWPane, SPane, OPane, bc, n, hBS, hBP, hGauss, hDiff: integer;
var t, StartFrq, Rate: float;
SetColorScheme( #Green, #Red, #Blue, #Black, #Black, #White );
bc := BarCount;
StartFrq := Trunc( bc / 100 );
Rate := Trunc( bc / 25 );
{* Create and plot a chirped sine wave, decreasing frequency *}
CSW := CreateSeries;
n := bc - 1;
for Bar := 0 to bc - 1 do
begin
  t := Bar / bc;
  @CSW[n] := Sin( 360 * ( StartFrq + t * Rate ) * t );
  Dec( n );
end;
CSWPane := CreatePane( 100, true, true );
PlotSeriesLabel( CSW, CSWPane, #Lime, #Thin, 'Chirped Sine' );
{* Run the Chirped signal through the filters and plot *}
SPane := CreatePane( 100, true, true );
hBS := SWAKSeries( CSW, 21, 'BS' );
PlotSeriesLabel( hBS, SPane, #Red, #Thin, 'SWAK BandStop(21)' );
hBP := SWAKSeries( CSW, 21, 'BP' );
PlotSeriesLabel( hBP, SPane, #Yellow, #Dotted, 'SWAK BandPass(21)' );
{* Predictive oscillator *}
OPane := CreatePane( 100, false, false );
hDiff := SubtractSeries( SWAKSeries( #Close, 19, 'BP' ), SWAKSeries( #Close, 21, 'BP' ) );
PlotSeriesLabel( hDiff, OPane, #Lime, #Histogram, 'SWAK BP(19)-BP(21)' );
{* Plot the SWAK Gaussian of the #Close series *}
hGauss := SWAKSeries( #Close, 50, 'Gauss' );
PlotSeriesLabel( hGauss, 0, #Yellow, #Thin, 'SWAK Gauss(50)' );
HideVolume;
--Robert Sucher
www.wealth-lab.com
GO BACK

AMIBROKER: SWISS ARMY KNIFE INDICATOR (SWAK)

In "Swiss Army Knife Indicator," John Ehlers presents an indicator that is based on the second-order infinite impulse response (IIR) filter. IIR filters are widely used in almost every digital signal processing application. In the code listing given here, we have presented AmiBroker's implementation of the SWAK indicator (second-order IIR filter). Included is some sample code that produces a point-change chart and IIR-filtered output. After applying the indicator, the parameter window (Figure 3) can be used to control the type of filter used and its parameters, such as averaging period.

FIGURE 3: AMIBROKER, SWISS ARMY KNIFE INDICATOR. This AmiBroker screenshot shows a daily candlestick chart of MSFT (upper pane) and point-change plot with an IIR-based average. The parameter window shown in the upper part allows you to modify the averaging period in real time.
SetBarsRequired(100000,0);
PI = 3.1415926;
function Poly2ndOrder( input, N, c0, c1, b0, b1, b2, a1, a2 )
{
  output = input; // initialize for N first bars
  for( i = Max( N, 2 ); i < BarCount; i++ )
  {
     output[ i ] = c0[ i ] * ( b0 * input[ i ] +
                               b1 * input[ i - 1 ] +
                               b2 * input[ i - 2 ] ) +
                     a1 * output[ i - 1 ] +
                     a2 * output[ i - 2 ] -
                     c1 * input[ i - N ];
  }
  return output;
}
function SWAK( input, type, Period, delta )
{
  N = 0;
  an = 2 * PI / Period;
  c0 = b0 = 1;
  c1 = b1 = b2 = a1 = a2 = gamma1 = 0;
  beta1 = 2.415 * ( 1- cos( an ) );
  alpha = -beta1 + sqrt( beta1 ^ 2 + 2 * beta1 );
  alpha1 = ( cos( an ) + sin( an ) - 1 )/cos( an );
  if( type == "EMA" )
  {
    b0 = alpha1; a1 = 1 - alpha1;
  }
  if( type == "SMA" )
  {
    N = Period;
    c1 = b0 = 1/N; a1 = 1;
  }
  if( type == "Gauss" )
  {
    c0 = alpha ^ 2;
    a1 = 2 * ( 1- alpha ); a2 = -( 1 - alpha )*( 1 - alpha );
  }
  if( type == "Butter" )
  {
    c0 = ( alpha ^ 2 ) / 4;
    a1 = 2 * ( 1- alpha ); a2 = -( 1 - alpha )*( 1 - alpha );
    b1 = 2; b2 = 1;
  }
  if( type == "HP" )
  {
    c0 = 1 - alpha1 / 2;
    b1 = -1;
    a1 = 1 - alpha1;
  }
  if( type == "2PHP" )
  {
    c0 = ( 1 - alpha / 2 ) ^ 2;
    b1 = -2; b2 = 1; a1 = 2 * ( 1 - alpha ); a2 = - ( 1 - alpha ) ^ 2;
  }
  if( type == "BP" OR type == "BS" )
  {
    beta1 = cos( 2 * PI / Period );
    gamma1 = 1 / cos( 4 * PI * delta / Period );
    alpha = gamma1 - sqrt( gamma1 ^ 2 - 1 );
    a1 = beta1 * ( 1 + alpha );
    a2 = - alpha;
   if( type == "BP" )
   {
       c0 = ( 1 - alpha ) / 2;
       b2 = -1;
   }
   else
   {
       c0 = ( 1 + alpha ) / 2;
       b1 = - 2 * beta1;
       b2 = -1;
   }
  }
  return Poly2ndOrder( input, N, c0, c1, b0, b1, b2, a1, a2 );
}
// test code
P = C - C[ 0 ];
Plot( P, "Change", colorBlack );
type = ParamList("Type", "EMA|SMA|Gauss|Butter|HP|2PHP|BP|BS" );
period = Param("Period", 20, 1, 100, 1 );
delta = Param("Delta", 0.1, 0, 1, 0.01 );
Plot( SWAK( P, type, period, delta), type +_PARAM_VALUES(), colorRed );
--Tomasz Janeczko, AmiBroker.com
www.amibroker.com
GO BACK

eSIGNAL: SWISS ARMY KNIFE INDICATOR (SWAK)

For this month's article by John Ehlers, "Swiss Army Knife Indicator," we've provided the following formula for eSignal, "Swak.efs." The study plots the various indicators discussed in the article (Figure 4), according to the indicator selected under the Type parameter in the Edit Studies option. The study also has parameters for the price source (HL/2), N (0), period (20), and delta (0.1). To change the parameters, use the Edit Studies option of the Advanced Chart.

FIGURE 4: eSIGNAL, SWISS ARMY KNIFE INDICATOR. Here is a demonstration of the Swiss Army Knife indicator in eSignal.
/***************************************
Provided By : eSignal (c) Copyright 2005
Description:  Swiss Army Knife - by John F. Ehlers

Version 1.0  11/08/2005

Notes:
January 2006 Issue of Stocks and Commodities Magazine

* Study requires version 7.9 or higher.


Formula Parameters:                 Defaults:
Price                               HL/2
    [Open, High, Low, Close, HL/2, HLC/3, OHLC/4]
Type                                BP
    [EMA, SMA, Gauss, Butter, HP, 2PHP, BP, BS]
N                                   0
Period                              20
Delta                               .1
***************************************/


function preMain() {
    setStudyTitle("SWAK ");
    //setShowTitleParameters(false);
    setCursorLabelName("Filt", 0);
    setDefaultBarThickness(2, 0);
    
    var fp1 = new FunctionParameter("sPrice", FunctionParameter.STRING);
        fp1.setName("Price");
        fp1.addOption("Open");
        fp1.addOption("High");
        fp1.addOption("Low");
        fp1.addOption("Close");
        fp1.addOption("HL/2");
        fp1.addOption("HLC/3");
        fp1.addOption("OHLC/4");
        fp1.setDefault("HL/2");
    var fp2 = new FunctionParameter("sType", FunctionParameter.STRING);
        fp2.setName("Type");
        fp2.addOption("EMA");
        fp2.addOption("SMA");
        fp2.addOption("Gauss");
        fp2.addOption("Butter");
        fp2.addOption("HP");
        fp2.addOption("2PHP");
        fp2.addOption("BP");
        fp2.addOption("BS");
        fp2.setDefault("BP");
    var fp3 = new FunctionParameter("nN", FunctionParameter.NUMBER);
        fp3.setName("N");
        fp3.setLowerLimit(0);
        fp3.setDefault(0);
    var fp4 = new FunctionParameter("nPeriod", FunctionParameter.NUMBER);
        fp4.setName("Period");
        fp4.setLowerLimit(0);
        fp4.setDefault(20);
    var fp5 = new FunctionParameter("nDelta", FunctionParameter.NUMBER);
        fp5.setName("Delta");
        fp5.setDefault(.1);
}

var bVersion = null;
var nBarCount = 0;

var bInit = false;
var Filt = null;
var Filt_0 = null;
var Filt_1 = null;
var Filt_2 = null;
var xPrice = null;

var c0 = 1;
var c1 = 0;
var b0 = 1;
var b1 = 0;
var b2 = 0;
var a1 = 0;
var a2 = 0;
var alpha = 0;
var beta1 = 0;
var gamma1 = 0;
var delta1 = .1

function main(sPrice, sType, nN, nPeriod, nDelta) {    

    if (bVersion == null) bVersion = verify();
    if (bVersion == false) return;    

    if (bInit == false) {
        switch (sPrice) {
            case "Open" :
                xPrice = open();
                break;
            case "High" :
                xPrice = high();
                break;
            case "Low" :
                xPrice = low();
                break;
            case "Close" :
                xPrice = close();
                break;
            case "HL/2" :
                xPrice = hl2();
                break;
            case "HLC/3" :
                xPrice = hlc3();
                break;
            case "OHLC/4" :
                xPrice = ohlc4();
                break;
            default: xPrice = hl2();
        }
        delta1 = nDelta;
        bInit = true;
    }

    if (getCurrentBarCount() > nN) {
        Filt = efsInternal("calcFilt", sType, nPeriod, nN, getSeries(xPrice));
        return Filt.getValue(0);
    } else {
        return;
    }
}


/***** Support Functions *****/

function calcFilt(type, Period, N, Price) {
    if (getBarState() == BARSTATE_NEWBAR) {
        nBarCount++;
        Filt_2 = Filt_1;
        Filt_1 = Filt_0;
    }
    
    switch (type) {
        case "EMA" :
            if (nBarCount <= N) {
                Filt_0 = Price.getValue(0);
                return Filt_0;
            }
            alpha = (Math.cos((2*Math.PI)/Period) + Math.sin((2*Math.PI)/Period)
                     - 1) / Math.cos((2*Math.PI)/Period);            
            b0 = alpha;
            a1 = 1 - alpha;
            break;
        case "SMA" :
            if (nBarCount <= N) {
                Filt_0 = Price.getValue(0);
                return Filt_0;
            }
            if (N == 0) N = 1;
            c0 = 1;
            c1 = 1 / N;
            b0 = 1 / N;
            b1 = 0;
            b2 = 0;
            a1 = 1;
            a2 = 0;
            break;
        case "Gauss" :
            if (nBarCount <= N) {
                Filt_0 = Price.getValue(0);
                return Filt_0;
            }
            beta1 = 2.415*(1 - Math.cos((2*Math.PI) / Period));
            alpha = -beta1 + Math.sqrt(beta1*beta1 + 2*beta1);
            c0 = alpha*alpha;
            a1 = 2*(1 - alpha);
            a2 = -(1 - alpha)*(1 - alpha);
            break;
        case "Butter" :
            if (nBarCount <= N) {
                Filt_0 = Price.getValue(0);
                return Filt_0;
            }
            beta1 = 2.415*(1 - Math.cos((2*Math.PI) / Period));
            alpha = -beta1 + Math.sqrt(beta1*beta1 + 2*beta1);
            c0 = alpha*alpha / 4;
            b1 = 2;
            b2 = 1;
            break;
        case "HP" :
            if (nBarCount <= N) {
                Filt_0 = 0;
                return Filt_0;
            }
            alpha = (Math.cos((2*Math.PI)/Period) + Math.sin((2*Math.PI)/Period)
                     - 1) / Math.cos((2*Math.PI)/Period);
            c0 = 1 - alpha / 2;
            b1 = -1;
            a1 = 1 - alpha;
            break;
        case "2PHP" :
            if (nBarCount <= N) {
                Filt_0 = 0;
                return Filt_0;
            }
            beta1 = 2.415*(1 - Math.cos((2*Math.PI) / Period));
            alpha = -beta1 + Math.sqrt(beta1*beta1 + 2*beta1);
            c0 = (1 - alpha / 2)*(1 - alpha / 2);
            b1 = -2;
            b2 = 1;
            a1 = 2*(1 - alpha);
            a2 = -(1 - alpha)*(1 - alpha);
           break;
        case "BP" :
            if (nBarCount <= N+4) {
                Filt_0 = 0;
                return Filt_0;
            }
            beta1 = Math.cos((2*Math.PI) / Period);
            gamma1 = 1 / Math.cos((((2*Math.PI)+(2*Math.PI))*delta1) / Period);
            alpha = gamma1 - Math.sqrt(gamma1*gamma1 - 1);
            c0 = (1 - alpha) / 2;
            b2 = -1;
            a1 = beta1*(1 + alpha);
            a2 = -alpha;
            break;
        case "BS" :
            if (nBarCount <= N+4) {
                Filt_0 = 0;
                return Filt_0;
            }
            beta1 = Math.cos((2*Math.PI) / Period);
            gamma1 = 1 / Math.cos((((2*Math.PI)+(2*Math.PI))*delta1) / Period);
            alpha = gamma1 - Math.sqrt(gamma1*gamma1 - 1);
            c0 = (1 + alpha) / 2;
            b1 = -2*beta1;
            b2 = 1;
            a1 = beta1*(1 + alpha);
            a2 = -alpha;
            break;
    }
    
    Filt_0 = c0*(b0*Price.getValue(0) + b1*Price.getValue(-1) + b2*Price.getValue(-2))
              + a1*Filt_1 + a2*Filt_2 - c1*Price.getValue(-N);
    return Filt_0;
}


function verify() {
    var b = false;
    if (getBuildNumber() < 700) {
        drawTextAbsolute(5, 35, "This study requires version 7.9 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;
}
--Jason Keck
eSignal, a division of Interactive Data Corp.
800 815-8256, www.esignalcentral.com
GO BACK

NEUROSHELL TRADER: SWISS ARMY KNIFE INDICATOR (SWAK)

The Swiss Army Knife indicator presented by John Ehlers in this issue can be easily implemented in NeuroShell Trader using NeuroShell Trader's ability to call external dynamic linked libraries (DLL). Dynamic linked libraries can be written in C, C++, Power Basic, IBasic, and Delphi.

After moving the EasyLanguage code given in the article to your preferred compiler and creating a DLL you can insert the resulting Swiss Army custom indicator as follows:

1. Select "New Indicator ..." from the Insert menu.
2. Select the Custom Indicator category.
3. Select the "Swiss Army Knife Indicator."
4. Select the parameters as you desire.
5. Select the Finished button.


If you decide to use the Swiss Army Knife indicator in a prediction or a trading strategy, the parameters can be optimized by the Genetic Algorithm built into NeuroShell Trader Professional. A sample chart is shown in Figure 5.


FIGURE 5: NeuroShell, SWISS ARMY KNIFE INDICATOR. Here is a sample NeuroShell chart demonstrating the various responses available with the Swiss Army Knife indicator as described by John Ehlers in this issue.


Users of NeuroShell Trader can go to the STOCKS & COMMODITIES section of the NeuroShell Trader free technical support website at www.NeuroShell.com to download a copy of the C code and corresponding DLL, along with a copy of the chart that includes the Swiss Army Knife indicator (no programming required).

It should be noted that John Ehlers's Mesa cycle indicators and cybernetic analysis indicators are also available as add-ons to NeuroShell Trader. For more information on these add-ons or on NeuroShell Trader, visit www.NeuroShell.com.

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

NEOTICKER: SWISS ARMY KNIFE INDICATOR (SWAK)

The indicator presented in the article "Swiss Army Knife Indicator" by John Ehlers can be implemented in NeoTicker using our formula language. The name of the indicator is "Tasc Swiss Army Knife" (Listing 1). It has five parameters:

Price--Formula parameter; generate average price for price calculation
Type--String parameter; selection for type of transformation to apply
N--Real parameter
Period--Integer parameter greater than zero
Delta1--Real parameter

The first part of the code has assigned to it a list of constant values. These constants will make rest of the code more readable.

The first parameter is used in the fml indicator call. This call produces an average price series. The second parameter type is converted to constant values from the constant assignment part. The next three parameters are assigned to named variables. These assignments are an effort to make the code more readable.

The calculator for c0, c1, b0, b1, b2, a1, and a2 is done according to the type of transformation that is chosen. Then "Flit" is calculated according to the source shown in the article.

This indicator, when applied to a data series, will return a transformation result (Figure 6).

FIGURE 6: NEOTICKER, SWISS ARMY KNIFE INDICATOR. Applying the indicator to a data series in NeoTicker will return a transformation result.


A downloadable version of this indicator will be available at the NeoTicker Yahoo! User Group.

'Constant
$EMA:=1;
$SMA:=2;
$Gauss:=3;
$Butter:=4;
$HP:=5;
$2PHP:=6;
$BP:=7;
$BS:=8;
'Converting Parameter Values
myPrice := fml(data1, param1);
$Type := choose(paramis(2, "EMA"),$EMA,paramis(2, "SMA"),$SMA,
                paramis(2, "Gauss"),$Gauss,paramis(2, "Butter"),$Butter,
                paramis(2, "HP"),$HP,paramis(2, "2PHP"),$2PHP,
                paramis(2, "BP"),$BP,paramis(2, "BS"),$BS,0);
$N := param3;
$myPeriod := param4;
$delta := param5;
'assignment calculation values
$gamma1 := if($Type=$BP or $Type=$BS,
               1/cos(720*$delta1/$myPeriod), 0);
$beta1 := choose($Type=$Gauss or $Type=$Butter or $Type=$2PHP,
                  2.415*(1-cos(360/$myPeriod)),
                 $Type=$BP or $Type=$BS,
                 cos(360/$myPeriod), 0);
$alpha := choose($Type=$EMA or $Type=$HP,
                 (cos(360/$myPeriod)+sin(360/$myPeriod)-1)/cos(360/$myPeriod),
                 $Type=$Gauss or $Type=$Butter or $Type=$2PHP,
                 -1*$beta1+sqrt($beta1*$beta1+2*$beta1),
                 $Type=$BP or $Type=$BS,
                 $gamma1-sqrt($gamma1*$gamma1-1), 0);
$c0 := choose($Type=$Gauss, $alpha*$alpha,
              $Type=$Butter, $alpha*$alpha/4,
              $Type=$HP, 1-$alpha/2,
              $Type=$2PHP, (1-$alpha/2)*(1-$alpha/2),
              $Type=$BP, (1-$alpha)/2,
              $Type=$BS, (1+$alpha)/2, 1);
$c1 := if($Type=$SMA,if($N=0, 0, 1/$N), 0);
$b0 := choose($Type=$EMA,$alpha,$Type=$SMA,if($N=0, 0, 1/$N),1);
$b1 := choose($Type=$Butter,2,$Type=$HP,-1,
              $Type=$2PHP,-2,$Type=$BS,-2*$beta1,0);
$b2 := choose($Type=$Butter or $Type=$2PHP or $Type=$BS,1,
              $Type=$BP,-1,0);
$a1 := choose($Type=$EMA or $Type=$HP,1-$alpha,
              $Type=$SMA,1,
              $Type=$2PHP or $Type=$Gauss,2*(1-$alpha),
              $Type=$BP or $Type=$BS, $beta1*(1+$alpha),0);
$a2 := choose($Type=$Gauss or $Type=$2PHP,-1*(1-$alpha)*(1-$alpha),
              $Type=$BP or $Type=$BS,-1*$alpha,0);
Flit := if(data1.barsnum(0)<=$N,
           if($Type=$HP or $Type=$2PHP,0,myPrice),
           $c0*($b0*myPrice+$b1*myPrice(1)+$b2*myPrice(2))+
           $a1*Flit(1)+$a2*Flit(2)-$c1*myPrice($N));
plot1 := Flit;
--Kenneth Yuen, TickQuest Inc.
www.tickquest.com
GO BACK

TRADING SOLUTIONS: SWISS ARMY KNIFE INDICATOR (SWAK)

In "Swiss Army Knife Indicator" in this issue, John Ehlers provides a general parameterized indicator that can replicate the behaviors of many different kinds of filters.

These functions can be entered into TradingSolutions as follows. 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. As with many indicators, these functions could make good inputs to neural network predictions.

Function Name: Swiss Army Knife Indicator
Short Name: SWAK
Inputs: Price, c0, c1, N, b0, b1, b2, a1, a2, Initial Value
If (GT (Bar# (), N), Add (Mult (c0, Add (Mult (b0, Price), Add (Mult (b1, Lag (Price, 1)),
 Mult (b2, Lag (Price, 2))))), Add (Mult (a1, Prev (1)), Sub (Mult (a2, Prev (2)), Mult
 (c1, Lag (Price, N))))), Initial Value)
Here is an example of implementing an Ema using Swak:
Function Name: SWAK Alpha for One-Pole Filter
Short Name: SWAK_OnePoleAlpha
Inputs: Period
Div (Add (Cos (DtoR (Div (360, Period))), Sub (Sin (DtoR (Div (360,Period))), 1)), Cos
 (DtoR (Div (360,Period))))
Function Name: SWAK Exponential Moving Average
Short Name: SWAK_EMA
Inputs: Price, Period
SWAK (Price,1,0,0,SWAK_OnePoleAlpha (Period),0,0,Sub (1,SWAK_OnePoleAlpha (Period)),0,Price)


Additional examples of implementing indicators using SWAK can be found at the TradingSolutions website (www.tradingsolutions.com) in the Solution Library section or at our website at Traders.com.

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

FINANCIAL DATA CALCULATOR: SWISS ARMY KNIFE INDICATOR (SWAK)

The article "Swiss Army Knife Indicator" by John Ehlers produces a general-purpose indicator that includes a number of indicator types. All of these types, and many more, are special cases of the FDC filter function, available as a basic function in FDC Professional. The filter function will compute any filter that has a rational transfer function.

Let us rewrite the SWAK transfer function as follows:

Output/Input = (b0 + b1Z-1 + b2Z-2 - bNZ-N )/(1 - a1Z-1 - a2Z-2)


where we have multiplied out and renamed the constants for simplicity.

Then, to compute the corresponding indicator with the filter function, simply enter the following line:

'- bN  b2  b1  b0 ; a2  a1' filter dataset


where actual numbers are substituted for the symbols. Note that the order of the inputs is from past to future, and this is the reverse of the order shown in the article. Notice also that the b's and a's are separated by a semicolon, and the entire expression is enclosed in quotes.

Here, we illustrate the FDC code for the various special cases given in the article. For clarity, we will choose actual numbers for the parameters. You can then replace these numbers by any desired values.

1. Exponential moving average with alpha = 0.2:
'.2;.8' filter dataset
This is equivalent with the Fdc expression:
.2 expave dataset
or, to use the corresponding equivalent number of days (9):
9 expave dataset
2. Simple five-day moving average using the Ehlers method: Normally, this
   is produced in Fdc by the input:
5 movave dataset
Ehlers's code used in the article would translate to:
'-.2 0 0 0 .2;1' filter dataset


This will initialize the beginning output to dataset values, but that will not produce the standard five-day moving average. This particular example, unlike the others in the article, is quite sensitive to initial conditions, and will not recover from an improper initial value. If the initial value is changed by a constant, that constant will persist forever. The outputs corresponding to different initial values will all have the same shape, but will differ by constants. The proper initialization is the ordinary average of the first three days' prices. In the filter function, you can override default initial values by inserting another semicolon followed by the desired numbers. In addition, you can use FDC expressions instead of actual numbers. For example, the input:

'-.2 0 0 0 .2;1;(totave dataset first 5)' filter dataset


will reproduce the standard five-day moving average.

3. Two-pole Gaussian filter with alpha = 0.2
'04; -.64 1.6' filter dataset


In general, if alpha is assigned to the variable a, we could use the expression:
'(a^2);(-(1-a)^2),(2*(1 - a))' filter dataset

The other examples can be similarly translated to FDC format by using the basic filter syntax expression shown at the beginning.

--Robert C. Busby, 856 857-9088
Mathematical Investment Decisions Inc.
rbusby@mathinvestdecisions.com
www.financialdatacalculator.com
GO BACK

VT TRADER: SWISS ARMY KNIFE INDICATOR (SWAK)

John Ehlers's article in this issue, "Swiss Army Knife Indicator," introduces an indicator by the same name. The SWAK indicator is a unique indicator consisting of 10 different responses ranging from oscillators to smoothers to bandpass and band-stop filters.

We'll be offering the SWAK indicator as a downloadable .vtscr indicator file in our user forums. The VTtrader code and instructions for creating this indicator are as follows (each input variable has been parameterized to allow customization):

1. Navigator Window>Tools>Indicator Builder>[New] button
2. In the Indicator Bookmark, type the following text for each field:
Name: Swiss Army Knife Indicator
Short Name: vt-SWAK
Label Mask: Swiss Army Knife Indicator (%Price%, %Period%, Delta: %_Delta%, Filter:
 %FilterType:ls%)
Placement: New Frame
Inspect Alias: Swiss Army Knife Indicator
3. In the Input Bookmark, create the following variables:
[New] button... Name: Price , Display Name: Price , Type: price , Default: Median Price
[New] button... Name: Period , Display Name: Periods , Type: integer , Default: 20
[New] button... Name: _Delta , Display Name: Delta , Type: float , Default: 0.0100
[New] button... Name: FilterType , Display Name: Filter Type , Type: Enumeration ,
 Default: click [...] button, [New] button, then create the following entries: Default,
 EMA, SMA, Gauss, Butter, Smooth, HighPass, TwoPole_HighPass, Bandpass, Band_stop; then,
 click [OK] button
Default: Bandpass (chosen from list created)
4. In the Output Bookmark, create the following variables:
[New] button...
Var Name: Filt_SWAK
Name: Filter
Line Color: dark blue
Line Width: slightly thicker
Line Type: solid line
5. In the Formula Bookmark, copy and paste the following formula:
{Provided By: Visual Trading Systems, LLC (c) Copyright 2006}
{Description: Swiss Army Knife Indicator by John F. Ehlers}
{Notes: January 2006 Issue - The MacGyver of Indicators - Swiss Army Knife Indicator}
{SWAK Version 1.0}
Num:= if(FilterType=2,
      if(Period=0,1,Period), 0);
_Beta:= if(FilterType=3 or FilterType=4 OR FilterType=7, 2.415 * (1-Cos(360/Period)),
        if(FilterType=8 or FilterType=9, Cos(360/Period),
        0));
_Gamma:= if(FilterType=8 or FilterType=9, 1 / Cos(720 * _Delta / Period),
         0);
Alpha:= if(FilterType=1 OR FilterType=6, (Cos(360/Period) + Sin(360/Period)-1)/Cos(360/Period),
        if(FilterType=3 or FilterType=4 OR FilterType=7, -_Beta + Sqrt(_Beta * _Beta + 2 * _Beta),
        if(FilterType=8 OR FilterType=9, _Gamma - Sqrt(_Gamma * _Gamma - 1),
        0)));
c0:= if(FilterType=3, alpha * alpha,
     if(FilterType=4, alpha * alpha / 4,
     if(FilterType=5, 1/4,
     if(FilterType=6 OR FilterType=8,(1 - alpha) / 2,
     if(FilterType=7,(1 - alpha / 2) * (1 - alpha / 2),
     if(FilterType=9,(1 + alpha) / 2,
     1))))));
c1:= if(FilterType=2 OR FilterType=10, 1/Num, 0);
b0:= if(FilterType=1, Alpha ,
     if(FilterType=2, 1/Num, 1));
b1:= if(FilterType=4 OR FilterType=5, 2,
     if(FilterType=6, -1,
     if(FilterType=7, -2,
     if(FilterType=9, -2 * _Beta,
     0))));
b2:= if(FilterType=4 OR FilterType=5 OR FilterType=7 OR FilterType=9, 1,
     if(FilterType=8, -1,
     0));
a1:= if(FilterType=1, 1 - alpha,
     if(FilterType=2 OR FilterType=10, 1,
     if(FilterType=3 OR FilterType=4 OR FilterType=7, 2 * (1 - alpha),
     if(FilterType=8, _Beta * (1 - alpha),
     if(FilterType=9, _Beta * (1 + alpha),
     0)))));
a2:= if(FilterType=3 OR FilterType=4 OR FilterType=7 , -(1 - alpha) * (1 - alpha),
     if(FilterType=5, -(1 - alpha) * (1 - alpha),
     if(FilterType=8 OR FilterType=9, -alpha,
     0)));
Filt:= if(prev=NULL, if(FilterType=6 OR FilterType=7, 0, Price),
       c0 * (b0 * Price + b1 * ref(Price,-1) + b2 * ref(Price,-2)
       + a1 * PREV + a2 * ref(PREV,-1) - c1 * ref(Price,- Num)));
 
Filt_SWAK:= if(CUM(1)<=Period, NULL, Filt);
6. Click the "Save" icon to finish building the Swak indicator.


To attach the SWAK indicator to a chart, right-click with the mouse within the chart window, select "Add Indicators," then "Swiss Army Knife Indicator" from the list. Users will have the ability to customize the parameters at this time. Once attached to the chart, the parameters can be customized by right-clicking with the mouse over the displayed indicator label and selecting "properties." Figure 7 shows a GBP/USD one-hour candlestick chart in VTtrader with the Swiss Army Knife indicator applying a band-stop filter to median price data.

FIGURE 7: VT TRADER, SWISS ARMY KNIFE INDICATOR. Here is a sample VTtrader GBP/USD one-hour candlestick chart with the SWAK indicator applying a 14-period band-stop filter to median price data.


To learn more about VT Trader, visit www.cmsfx.com.

--Vadim Sologubov and Chris Skidmore
Visual Trading Systems, LLC (courtesy of CMS Forex)
(866) 51-CMSFX, trading@cmsfx.com
GO BACK

TRADECISION: SWISS ARMY KNIFE INDICATOR (SWAK)

In "Swiss Army Knife Indicator," John Ehlers illustrates digital filtering concepts. With the Tradecision Indicator Builder, you can easily code the SWAK indicator. Here, we provide the Improvian language code for the SWAK indicator. Please note: According to our understanding of the author's idea, in the case of using SMA as the filter type, you need to set Period equal to the simple moving average (SMA) period.

The syntax for the SWAK indicator is as follows:

{Provided by: Alyuda Research, Inc © 2005,
Version: Tradecision 2.0
Description: SWISS ARMY KNIFE INDICATOR by John F. Ehlers,
"Swiss Army Knife Indicator," January 2006 issue of
 Technical Analysis of STOCKS & COMMODITIES magazine}
Input
     Price: "Price", (High+Low)/2;
     Type: "Type", "EMA";
     N: "SMA Period", 0, 0;
     Period: "Period", 20, 0;
     delta1: "Delta", 0;
end_input
var
   c0 := 1;
   c1 := 0;
   b0 := 1;
   b1 := 0;
   b2 := 0;
   a1 := 0;
   a2 := 0;
   alpha := 0;
   beta1 := 0;
   gamma1 := 0;
end_var


[Editor's note: For the rest of the Tradecision code, please see www.Traders.com or download the formula from the link given below.]

Once you code this indicator, you can plot it on a chart using the "Insert Into Chart" command (see sample chart in Figure 8). While inserting it, you can change parameters for the indicator.

FIGURE 8: TRADECISION, SWISS ARMY KNIFE INDICATOR. Here is the SWAK indicator (the red line) with the period set at 20, Gauss type, on a daily chart of YHOO.
You also can create the SWAK function that you can use as a trading rule or a neural model input. The SWAK function and indicator can be downloaded as "Swak.tfn" and "Swak.tnd" files from the Tradecision Knowledgebase at https://www.tradecision.com/knowledgebase.htm. You will need to import them in the Function and Indicator Builders.
--Alex Grechanowski
Alyuda Research, Inc.
347 416-6083, alex@alyuda.com
www.alyuda.com, www.tradecision.com
GO BACK

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


Return to January 2006 Contents