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. January 2007
TRADERS' TIPSYou 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: Fourier Transform For Traders
eSIGNAL: Fourier Transform For Traders
WEALTH-LAB: Transformed Discrete Fourier Transform
AMIBROKER: Fourier Transform For Traders
NEUROSHELL TRADER: Fourier Transform For Traders
TRADECISION: Fourier Transform For Traders
STRATASEARCH: FOURIER TRANSFORM FOR TRADERS
MULTICHARTS: Fourier Transform For Traders
AIQ: Entropic Analysis
VT TRADER: Going Beyond 70 and 30 In Forexor return to January 2007 Contents
Editor's note: Most of this month's Traders' Tips are based on John Ehlers' article in this issue, "Fourier Transform For Traders." Code written in EasyLanguage for TradeStation is provided by the author in the article's sidebar titled "Transformed DFT EasyLanguage code." Additional code is presented here.
Other tips in this section are on topics of the contributor's choosing.
Code can be copied and pasted from here into the appropriate program. In addition, the code for each program is usually available at the respective software company's website. Thus, no retyping of code is required for Internet users.
For subscribers, code found in John Ehlers' article can be copied and pasted into TradeStation from the Subscriber Area at https://technical.traders.com/sub/sublogin.asp. Login is required.
TRADESTATION: Fourier Transform For Traders
John Ehlers' article in this issue, "Fourier Transform For Traders," suggests using the discrete Fourier transform (DFT) to tune indicators. Here, we demonstrate this by building a DFT-adapted relative strength index (RSI) strategy (Figure 1).
FIGURE 1: TRADESTATION, DISCRETE FOURIER TRANSFORM (DFT) AND DFT-ADAPTED RELATIVE STRENGTH INDEX (RSI). In this daily chart of the continuous S&P 500 emini futures contract, the upper subgraph shows RSI_DFT strategy trades. The middle subgraph displays the RSI_DFT indicator. The original DFT is shown in the lower subgraph.
Rather than display the RSI for a single cycle length across the entire chart, our adaptive RSI value reflects the DFT-calculated dominant cycle length RSI. If the dominant cycle changes from 14 to 18 bars, the RSI length parameter changes accordingly. Computationally, this requires the strategy to continuously update values for all possible RSI cycle lengths via a "for" loop and array.Once the suite of possible RSI values is calculated, we use the DFT to select the relevant RSI for the current bar. The strategy then trades according to J. Welles Wilder's original rules for the RSI.
To download this EasyLanguage code, go to the Support Center at TradeStation.com. Search for the file "Ehlers_Dft.Eld."
Strategy: Ehlers DFT inputs: Price( MedianPrice ), Window( 50 ), { maximum Window = 50 } OverBought( 70 ), OverSold( 30 ), Frac( 0.5 ) ; variables: HP( 0 ), CleanedData( 0 ), Per( 0 ), CosPer( 0 ), CycPer( 0 ), Alpha1( 0 ), Period( 0 ), n( 0 ), MaxPwr( 0 ), Num( 0 ), Denom( 0 ), ThreeMinus( 0 ), DominantCycle( 0 ), Change( 0 ), AbsChange( 0 ), Count( 0 ), DFT_RSI( 0 ) ; { arrays are sized for a maximum period of 50 bars } arrays: CosinePart[50]( 0 ), SinePart[50]( 0 ), Pwr[50]( 0 ), DB[50]( 0 ), SF[50]( 0 ), NetChgAvg[50]( 0 ), TotchgAvg[50]( 0 ), RSIArray[50]( 0 ) ; { detrend data by high-pass filtering with a 40 period cut-off } if CurrentBar <= 5 then begin HP = Price ; CleanedData = Price ; end else if CurrentBar > 5 then begin Per = 360 / 40 ; CosPer = Cosine( Per ) ; if CosPer <> 0 then Alpha1 = ( 1 - Sine( Per ) ) / CosPer ; HP = 0.5 * ( 1 + Alpha1 ) * ( Price - Price[ 1 ] ) + Alpha1 * HP[1] ; CleanedData = ( HP + 2 * HP[1] + 3 * HP[2] + 3 * HP[3] + 2 * HP[4] + HP[5] ) / 12 ; end ; { calculate DFT } for Period = 8 to 50 begin CosinePart[Period] = 0 ; SinePart[Period] = 0 ; for n = 0 to Window - 1 begin CycPer = ( 360 * n ) / Period ; CosinePart[Period] = CosinePart[Period] + CleanedData[n] * Cosine( CycPer ) ; SinePart[Period] = SinePart[Period] + CleanedData[n] * Sine( CycPer ) ; end ; Pwr[Period] = Square( CosinePart[Period] ) + Square( SinePart[Period] ) ; end ; { find maximum power level for normalization } MaxPwr = Pwr[8] ; for Period = 8 to 50 begin if Pwr[Period] > MaxPwr then MaxPwr = Pwr[Period] ; end ; { normalize power levels and convert to decibels } for Period = 8 to 50 begin if MaxPwr > 0 and Pwr[Period] > 0 then DB[Period] = -10 * log( 0.01 / ( 1 - 0.99 * Pwr[Period] / MaxPwr ) ) / log( 10 ) ; if DB[Period] > 20 then DB[Period] = 20 ; end ; { find dominant cycle using CG algorithm } Num = 0 ; Denom = 0 ; for Period = 8 to 50 begin if DB[Period] < 3 then begin ThreeMinus = 3 - DB[Period] ; Num = Num + Period * ThreeMinus ; Denom = Denom + ThreeMinus ; end ; end ; if Denom <> 0 then DominantCycle = Num / Denom ; Change = Price - Price[1] ; AbsChange = AbsValue( Change ) ; for Count = 1 to Window begin if CurrentBar = 1 then begin SF[Count] = 1 / Count ; NetChgAvg[Count] = ( Price - Price[Count] ) / Count ; TotChgAvg[Count] = Average( AbsChange, Count ) ; end else begin NetChgAvg[Count] = NetChgAvg[Count][1] + SF[Count] * ( Change - NetChgAvg[Count][1] ) ; TotChgAvg[Count] = TotChgAvg[Count][1] + SF[Count] * ( AbsChange - TotChgAvg[Count][1] ) ; if TotChgAvg[Count] <> 0 then RSIArray[Count] = ( 50 * ( NetChgAvg[Count] / TotChgAvg[Count] + 1 ) ) else RSIArray[Count] = 50 ; end ; end ; DFT_RSI = RSIArray[ iff( Frac * DominantCycle < 50, Frac * DominantCycle, 50 ) ] ; { CB > 1 check used to avoid spurious cross confirmation at CB = 1 } if Currentbar > 1 then begin if DFT_RSI crosses over OverSold then Buy ( "RSI-LE" ) next bar at market ; if DFT_RSI crosses under OverBought then Sell Short ( "RSI-SE" ) next bar at market ; end ;--Mark Mills
TradeStation Securities, Inc.
A subsidiary of TradeStation Group, Inc.
www.TradeStation.com
eSIGNAL: Fourier Transform For Traders
For this month's Traders' Tip based on John Ehlers' article in this issue, "Fourier Transform For Traders," we have provided the eSignal formula "TransformedDFT.efs."
There are several formula parameters that may be configured through the Edit Studies option in the Advanced Chart. There is an option to highlight the dominant cycle (DC), which is off by default. When the option for displaying the DC is on, the default color and size is blue and "2," respectively. Both properties of the DC may also be modified through Edit Studies.
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. The eSignal formula script (EFS) is also available for copying and pasting from the STOCKS & COMMODITIES website at Traders.com.
FIGURE 2: eSIGNAL, DISCRETE FOURIER TRANSFORM. Here is a demonstration of the transformed discrete Fourier transform (DFT) in eSignal. There is an option to highlight the dominant cycle (DC), which is off by default. When the option for displaying the DC is on, the default color and size is blue and "2," respectively.
GO BACK/*************************************** Provided By : eSignal (c) Copyright 2006 Description: Fourier Transform for Traders by John Ehlers Version 1.0 11/02/2006 Notes: * Jan 2007 Issue of Stocks and Commodities Magazine * Study requires version 8.0 or later. Formula Parameters: Default: Show Dominant Cycle false Dominant Cycle Color blue Dominant Cycle Size 2 *****************************************************************/ function preMain() { setStudyTitle("Transformed DFT "); setShowCursorLabel(false); setShowTitleParameters(false); // Dominant Cycle properties setPlotType(PLOTTYPE_CIRCLE, 51); var fp1 = new FunctionParameter("bShowDC", FunctionParameter.BOOLEAN); fp1.setName("Show Dominant Cycle"); fp1.setDefault(false); var fp2 = new FunctionParameter("nDC_color", FunctionParameter.COLOR); fp2.setName("Dominant Cycle Color"); fp2.setDefault(Color.blue); var fp3 = new FunctionParameter("nDC_thick", FunctionParameter.NUMBER); fp3.setName("Dominant Cycle Size"); fp3.setLowerLimit(1); fp3.setDefault(2); } // Global Variables var bVersion = null; // Version flag var bInit = false; // Initialization flag var xPrice = null; var xHP = null; var xCleanData = null; var nWindow = 50; var nAlpha = (1 - Math.sin((2*Math.PI)/40)) / Math.cos((2*Math.PI)/40); var aCosinePart = new Array(51); var aSinePart = new Array(51); var aPwr = new Array(51); var aDB = new Array(51); var aReturn = new Array(52); // return array function main(bShowDC, nDC_color, nDC_thick) { if (bVersion == null) bVersion = verify(); if (bVersion == false) return; var nPeriod = 0; var n = 0; var nMaxPwr = 0; var nNum = 0; var nDenom = 0; var nDominantCycle = 0; var Color1 = null; var Color2 = null; //Initialization if (bInit == false) { setDefaultBarFgColor(nDC_color, 51); setDefaultBarThickness(nDC_thick, 51); xPrice = hl2(); xHP = efsInternal("calcHP", xPrice); xCleanData = efsInternal("calcCleanData", xHP); bInit = true; } var nHP = xHP.getValue(0); var nCleanData = xCleanData.getValue(-nWindow); if (nHP == null || nCleanData == null) return; //This is the DFT nPeriod = 8; n = 0; for (nPeriod = 8; nPeriod <= 50; nPeriod++) { aCosinePart[nPeriod] = 0; aSinePart[nPeriod] = 0; for (n = 0; n <= nWindow; n++) { var nCD = xCleanData.getValue(-n); aCosinePart[nPeriod] = aCosinePart[nPeriod] + nCD*Math.cos((2*Math.PI)*n/nPeriod); aSinePart[nPeriod] = aSinePart[nPeriod] + nCD*Math.sin((2*Math.PI)*n/nPeriod); } aPwr[nPeriod] = aCosinePart[nPeriod]*aCosinePart[nPeriod] + aSinePart[nPeriod]*aSinePart[nPeriod]; } //Find Maximum Power Level for Normalization nPeriod = 8; nMaxPwr = aPwr[nPeriod]; for (nPeriod = 8; nPeriod <= 50; nPeriod++) { if (aPwr[nPeriod] > nMaxPwr) nMaxPwr = aPwr[nPeriod]; } //Normalize Power Levels and Convert to Decibels nPeriod = 8; for (nPeriod = 8; nPeriod <= 50; nPeriod++) { if (nMaxPwr > 0 && aPwr[nPeriod] > 0) { aDB[nPeriod] = -10*Math.log(.01 / (1 - .99*aPwr[nPeriod] / nMaxPwr))/Math.log(10); } if (aDB[nPeriod] > 20) aDB[nPeriod] = 20; } //Find Dominant Cycle using CG algorithm nPeriod = 8; for (nPeriod = 8; nPeriod <= 50; nPeriod++) { if (aDB[nPeriod] < 3) { nNum += nPeriod*(3 - aDB[nPeriod]); nDenom += (3 - aDB[nPeriod]); } } if (nDenom != 0) { nDominantCycle = nNum/nDenom; if (bShowDC == true) { // Dominant Cycle aReturn[51] = nDominantCycle; } } //Plot the Spectrum as a Heatmap nPeriod = 8; for (nPeriod = 8; nPeriod <= 50; nPeriod++) { //Convert Decibels to RGB Color for Display if (aDB[nPeriod] > 10) { Color1 = Math.round(255*(2 - aDB[nPeriod]/10)); Color2 = 0; } else if (aDB[nPeriod] <= 10) { Color1 = 255; Color2 = Math.round(255*(1 - aDB[nPeriod]/10)); } aReturn[nPeriod] = nPeriod; setDefaultBarFgColor(Color.RGB(Color1 , Color2, 0), nPeriod); setDefaultBarThickness(4, nPeriod); } // aReturn[51] // contains the Dominant Cycle value return aReturn; } // calcHP globals var nPrevHP = null; var nCurrHP = null; function calcHP(x) { if (getCurrentBarCount() <= 5 ) { nCurrHP = x.getValue(0); return nCurrHP; } else { if (x.getValue(-1) == null) return null; if (getBarState() == BARSTATE_NEWBAR) nPrevHP = nCurrHP; nCurrHP = ( 0.5*(1 + nAlpha)*(x.getValue(0) - x.getValue(-1)) + nAlpha*nPrevHP ); return nCurrHP; } } function calcCleanData(x) { //Get a detrended version of the data by High Pass Filtering //with a 40 Period cutoff if (getCurrentBarCount() <= 5 ) { return x.getValue(0); } else { return ( x.getValue(0) + 2*x.getValue(-1) + 3*x.getValue(-2) + 3*x.getValue(-3) + 2*x.getValue(-4) + x.getValue(-5) ) / 12; } } 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; }
--Jason Keck
eSignal, a division of Interactive Data Corp.
800 815-8256, www.esignalcentral.com
WEALTH-LAB: Transformed Discrete Fourier Transform
This month's Traders' Tip, which is based on John Ehlers' article, "Fourier Transform For Traders," gives us an excuse to shake some dust off a rarely used indicator that's available in WealthLab's built-in library: the FIR (finite impulse response).
Here, we used it in two (conceptually different) ways: once to build the CleanedData series -- that is, a custom-weighted moving average -- and then to build several convolutions (against variable-period sines and cosines) that are needed when computing the periodogram.
The WealthScript code shown here also has a simple trading system to show how "standard" indicators may easily become adaptive; here, we show a simple moving average (whose length is dynamically set as one half of DominantCycle) and a linear regression (one quarter of DominantCycle). Trading is driven by their crossings (Figure 3).
FIGURE 3: WEALTH-LAB, FINITE IMPULSE RESPONSE. Notice how the "fast" line (variable-period linear regression, in red) closely follows prices, while the "slow" line (variable-period SMA, in blue) will normally stay away from the fast line but gets in sync quickly when trends are about to end.const Window = 50; // Transformed Discrete Fourier Transform -- Dominant Cycle function TDFT_DCSeries(Series: integer; BuildHeatMap: boolean): integer; begin var Name: string = 'TDFT_DC(' + GetDescription(Series) + ')'; Result := FindNamedSeries(Name); if (Result >= 0) and (not BuildHeatMap or (FindNamedSeries(Name + '.8') >= 0)) then exit; if Result < 0 then Result := CreateNamedSeries(Name); var Period, n, Bar: integer; var C, S, DominantCycle: float; var HeatMap: array[8..Window] of integer; if BuildHeatMap then for Period := 8 to Window do begin HeatMap[Period] := AddSeriesValue(CreateNamedSeries(''), Period); SetDescription(HeatMap[Period], Name + '.' + IntToStr(Period)); end; // Convert Decibels to RGB Color to Display var Color: array[0..18] of integer; for n := 0 to 9 do Color[n] := 990 - 10 * n; // yellow to red for n := 10 to 18 do Color[n] := 1800 - 100 * n; // red to black // Get detrended data by High Pass Filtering with a 40 Period cutoff var Alpha: float = (1 - Sin(360 / 40)) / Cos(360 / 40); var HP: integer = CreateSeries; for Bar := 1 to BarCount - 1 do @HP[Bar] := Alpha * @HP[Bar - 1] + Momentum(Bar, Series, 1) * (1 + Alpha) / 2; var CleanedData: integer = FIRSeries(HP, '1,2,3,3,2,1'); // Prepare convolution series for DFT var CConv, SConv: array[8..Window] of integer; var CSum, SSum: array[8..Window] of float; for Period := 8 to Window do begin var CW: string = ''; var SW: string = ''; CSum[Period] := 1; SSum[Period] := 1; for n := 0 to Window - 1 do begin C := Round(Cos(360 * n / Period) * 100000); S := Round(Sin(360 * n / Period) * 100000); CW := CW + FloatToStr(C) + ','; SW := SW + FloatToStr(S) + ','; CSum[Period] := CSum[Period] + C; SSum[Period] := SSum[Period] + S; end; CConv[Period] := FIRSeries(CleanedData, CW + '1'); SConv[Period] := FIRSeries(CleanedData, SW + '1'); end; for Bar := Window + 4 to BarCount - 1 do begin // This is the DFT var MaxPwr: float = 0; var Pwr: array[8..Window] of float; for Period := 8 to Window do begin C := GetSeriesValue(Bar, CConv[Period]) * CSum[Period]; S := GetSeriesValue(Bar, SConv[Period]) * SSum[Period]; Pwr[Period] := C * C + S * S; // Find Maximum Power Level for Normalization MaxPwr := max(MaxPwr, Pwr[Period]); end; // Find Dominant Cycle using CG algorithm var Num: float = 0; var Den: float = 0; for Period := 8 to Window do if (Pwr[Period] > 0) then begin // Normalize Power Levels and Convert to Decibels var DB: float = 20 + 10 * Log10(1 - 0.99 * Pwr[Period] / MaxPwr);
AMIBROKER: Fourier Transform For Traders
In "Fourier Transform For Traders" in this issue, John Ehlers presents an interesting technique of improving the resolution of spectral analysis that could be used to effectively measure market cycles. Better resolution is obtained by a surprisingly simple modification of the discrete Fourier transform.
Implementing the idea presented in the article is easy using AmiBroker's Formula Language. Listing 1 shows the full-featured formula that implements a high-pass filter and a six-tap low-pass finite impulse response (FIR) filter on input, then does discrete Fourier transform calculations and plots a spectrogram as a heat map (Figure 4). We have taken liberty of adding extra parameters so the user can modify the analysis window length and the high-pass filter cutoff frequency in real time using the parameters window. Changing parameters on the fly and seeing the evolution of the spectrogram is not only educational but also entertaining.
FIGURE 4: AMIBROKER, TRANSFORMED DISCRETE FOURIER TRANSFORM (DFT). This screenshot shows a daily chart of IBM (upper pane) and the transformed DFT spectral estimate that allows us to clearly identify the variable dominant cycle. This chart effectively duplicates the results presented in John Ehlers' article.Listing 1 PI = 3.1415926; Data = (H+L)/2; // detrending ( high-pass filter ) HFPeriods = Param("HP filter cutoff", 40, 20, 100 ); alpha1 = ( 1-sin(2*pi/HFPeriods) ) / cos( 2 * pi / HFPeriods ); HP = AMA2( Data - Ref( Data, -1 ), 0.5 * ( 1 + alpha1 ), alpha1 ); // 6-tap low-pass FIR filter CleanedData = ( HP + 2 * Ref( HP, -1 ) + 3 * Ref( HP, -2 ) + 3 * Ref( HP, -3 ) + 2 * Ref( HP, -4 ) + Ref( HP, -5 ) )/12; // Discrete Fourier Transform WindowSize = Param("Window Size", 50, 20, 100 ); Maxpwr = 0; x = BarIndex(); for( period = 8; period <= WindowSize; period++ ) { tx = 2 * pi * x / period; cosinepart = Sum( CleanedData * cos( tx ), WindowSize ); sinepart = Sum( CleanedData * sin( tx ), WindowSize ); pwr = cosinepart ^ 2 + sinepart ^ 2; Maxpwr = Max( Maxpwr, pwr ); VarSet( "pwr"+period, pwr ); } // Normalize and convert to decibels for( period = 8; period <= WindowSize; period++ ) { pwr = VarGet("pwr"+period); db = -10 * log10( 0.01 / ( 1 - 0.99 * pwr / Maxpwr ) ); db = Min( db, 20 ); // 'saturate' at -20db VarSet( "db"+period, db ); } Title = Name() + " HiRes DFT : "; // Plot Heat Map ( Spectrogram ) // and find dominant cycle DcNum = DcDenom = 0; for( k = 8; k <= WindowSize; k++ ) { db = VarGet("db"+k); // convert dB to color Red = IIf( db > 10, 255 * ( 2 - db/10 ), 255 ); Green = IIf( db <= 10, 255 * ( 1 - db/10 ), 0 ); PlotOHLC( k, k, k-1, k-1, "", ColorRGB( Red, Green, 0 ), styleCloud | styleNoLabel); if( SelectedValue( db ) <= 5 ) Title = Title + k + " = " + StrFormat("%.2lf",-db) + "dB, "; // dominant cycle calcs DcNum = DcNum + (db < 3 ) * k * ( 3 - db ); DcDenom = DcDenom + ( db < 3 ) * ( 3 - db ); } if( ParamToggle("Show Dom. Cycle?", "No|Yes" ) ) { DominantCycle = DcNum / DcDenom; Plot( DominantCycle, "Dominant Cycle", colorBlue ); Title = Title + "{{VALUES}}"; } GraphZOrder = 1;
--Tomasz Janeczko, AmiBroker.com
www.amibroker.com
NEUROSHELL TRADER: Fourier Transform For Traders
The dominant cycle indicator introduced by John Ehlers in his article in this issue, "Fourier Transform For Traders," can be easily implemented in NeuroShell Trader using NeuroShell Trader's ability to call indicators written in common programming languages such as C, C++, Power Basic, IBasic, or Delphi.
After converting the EasyLanguage code given in the article to your preferred compiler, you can insert the resulting dominant cycle indicator as follows:
1. Select "New Indicator ..." from the Insert menu.If you decide to use the dynamic cycle indicator in a prediction or trading strategy, the parameters can be optimized by the Genetic Algorithm built into NeuroShell Trader Professional.
2. Choose the External Program & Library Calls category.
3. Select the appropriate External Call indicator.
4. Set up the parameters to match your program inputs.
5. Select the Finished button.A dynamic trading system can be easily created in NeuroShell Trader by combining the Dynamic Cycle indicator with the adaptive-length indicators available in John Ehlers' Cybernetic and Mesa8 NeuroShell Trader add-ons. John Ehlers suggests that adaptive-length indicators linked to the dominant cycle indicator, when combined with NeuroShell Trader's genetic optimizer, could produce very robust systems. Similar strategies may also be created using the Dominant Cycle indicator found in John Ehlers' Mesa8 NeuroShell Trader Add-on.
FIGURE 5: NEUROSHELL, FOURIER TRANSFORM. Here is a sample NeuroShell chart demonstrating the dominant cycle indicator.
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 any previous Traders' Tips.--Marge Sherald, Ward Systems Group, Inc.
301 662-7950, sales@wardsystems.com
www.neuroshell.com
TRADECISION: Fourier Transform For Traders
In "Fourier Transform For Traders" in this issue, John Ehlers explains how to use Fourier transforms for measuring and estimating market cycles. Tradecision's Indicator Builder enables you to create a custom indicator using the method that Ehlers describes.
This indicator allows you to build only some of the price data spectrum components, defined by the parameter Peridq. The parameter Peridq is the component to be analyzed with the fluctuations for the indicated period. If the parameter ShowDC is true, Peridq is invalid, and the graph shows the behavior of the dominant cycle component, calculated automatically.
Here is the code for the Fourier custom indicator:
Input Price :"Price" ,((H+L)/2); Window:"Window",50; ShowDC:"ShowDC",false; Peridq:"Period",30,1,50; end_input var alpha1:=0; HP:=0; CleanedData:=0; Period:=0; n:=0; MaxPwr:=0; Num:=0; Denom:=0; DominantCycle:=0; array:CosinePart[50]:=0; array:SinePart[50]:=0; array:Pwr[50]:=0; array:DB[50]:=0; end_var {Get a detrended version of the data by High Pass Filtering with a 40 Period cutoff} If HISTORYSIZE <= 5 Then Begin HP := Price; CleanedData := Price; End; else Begin alpha1 := (1 - Sin(360/40))/Cos(360/40); HP := 0.5*(1 + alpha1)*(Price - Price\1\) + alpha1*HP\1\; CleanedData := (HP + 2*HP\1\ + 3*HP\2\ + 3*HP\3\ + 2*HP\4\ + HP\5\)/12; End; {This is the DFT} For Period := 8 to 50 do Begin CosinePart[Period] := 0; SinePart[Period] := 0; For n := 0 to Window - 1 do Begin CosinePart[Period] := CosinePart[Period] + CleanedData\n\*Cos(360*n/Period); SinePart[Period] := SinePart[Period] + CleanedData\n\*Sin(360*n/Period); End; Pwr[Period] := CosinePart[Period]*CosinePart[Period] + SinePart[Period]*SinePart[Period]; End; {Find Maximum Power Level for Normalization} MaxPwr := Pwr[8]; For Period := 8 to 50 do Begin If Pwr[Period] > MaxPwr Then MaxPwr := Pwr[Period]; End; {Normalize Power Levels and Convert to Decibels} For Period := 8 to 50 do Begin IF MaxPwr > 0 and Pwr[Period] > 0 Then DB[Period] := - 10* LogN(0.01 / (1 - 0.99*Pwr[Period] / MaxPwr))/LogN(10); If DB[Period] > 20 then DB[Period] := 20; End; If ShowDC = True then Begin {Find Dominant Cycle using CG algorithm} Num := 0;Denom := 0; For Period := 8 to 50 do Begin If DB[Period] < 3 Then Begin Num := Num + Period*(3 - DB[Period]); Denom := Denom + (3 - DB[Period]); End; End; If Denom <> 0 then DominantCycle := Num/Denom; this:=DominantCycle; End; Else this :=DB[Peridq]; return this;
To import the indicator into Tradecision, visit the "Traders' Tips from Tasc magazine" at https://tradecision.com/support/tasc_tips/tasc_traders_tips.htm or copy the code from the STOCKS & COMMODITIES website at www.Traders.com. A sample chart is shown in Figure 6.FIGURE 6: TRADECISION, FOURIER. Here is John Ehlers' Fourier indicator, inserted here as a subchart on an IBM daily chart.
--Alex Grechanowski
Alyuda Research, Inc.
sales@alyuda.com, 510 931-7808
www.tradecision.com
STRATASEARCH: Fourier Transform For Traders
As John Ehlers states in his article in this issue, "Fourier Transform For Traders," the transformed discrete Fourier transform (DFT) indicator may not be perfect, but it's better than driving in the fog. However, when it's combined with the right combination of additional indicators, the transformed DFT can be an integral part of a complete trading system by helping to identify cyclic versus trending periods and helping to identify the length of those periods.
StrataSearch allows you to automatically run and test the transformed DFT alongside a variety of other indicators and trading rules. With this approach, you can easily identify trading rules that work well with the transformed DFT.
A sample chart is shown in Figure 7.
FIGURE 7: STRATASEARCH, TRANSFORMED DISCRETE FOURIER TRANSFORM (DFT). The variable dominant cycle can be clearly identified using the transformed DFT.As with all our other StrataSearch Traders' Tips contributions, additional information -- including plug-ins -- can be found in the Shared Area of our user forum. This month's plug-in also contains a number of prebuilt trading rules that will allow you to include this indicator in your automated searches. Simply install the plug-in and launch your automated search.
Here is what the code looks like: //**************************************************************** // Transformed DFT //**************************************************************** TRANSFORMEDDFT_API int TransformedDFT(Prices *pPrices, Values *pResults, int nTotDays, Values *pValue1, Values *pValue2) { double alpha1; double *HP; double *CleanedData; int Period; int n; double MaxPwr; double Num; double Denom; double DominantCycle; int CurrentBar; double *Price; int Window; // Arrays are sized to have a maximum Period of 50 bars double CosinePart[51]; double SinePart[51]; double Pwr[51]; double DB[51]; Window = (int) pValue2->dValue; if(Window < 8) Window = 8; if(Window > 50) Window = 50; Price = (double *) malloc(sizeof(double) * nTotDays); ZeroMemory(Price, sizeof(double) * nTotDays); HP = (double *) malloc(sizeof(double) * nTotDays); ZeroMemory(HP, sizeof(double) * nTotDays); CleanedData = (double *) malloc(sizeof(double) * nTotDays); ZeroMemory(CleanedData, sizeof(double) * nTotDays); for(CurrentBar=0; CurrentBar<nTotDays; CurrentBar++) { ZeroMemory(CosinePart, sizeof(CosinePart)); ZeroMemory(SinePart, sizeof(SinePart)); ZeroMemory(Pwr, sizeof(Pwr)); ZeroMemory(DB, sizeof(DB)); Price[CurrentBar] = pValue1[CurrentBar].dValue; // Get a detrended version of the data by High Pass Filtering with a 40 Period cutoff if(CurrentBar <= 5) { HP[CurrentBar] = Price[CurrentBar]; CleanedData[CurrentBar] = Price[CurrentBar]; } if(CurrentBar > 5) { alpha1 = (1 - sin(DegreesToRadians(360/40)))/cos(DegreesToRadians(360/40)); HP[CurrentBar] = .5*(1+alpha1)*(Price[CurrentBar] - Price[CurrentBar-1])+alpha1*HP[CurrentBar-1]; CleanedData[CurrentBar] = (HP[CurrentBar] + 2*HP[CurrentBar-1] + 3*HP[CurrentBar-2] + 3*HP[CurrentBar-3] + 2*HP[CurrentBar-4] + HP[CurrentBar-5])/12; } // Continue if there isn't sufficient data if(CurrentBar-Window < 0) { pResults[CurrentBar].dValue = 0; pResults[CurrentBar].chIsValid = 0; continue; } // This is the DFT for(Period=8; Period<=50; Period++) { CosinePart[Period] = 0; SinePart[Period] = 0; for(n=0; n<=Window-1; n++) { CosinePart[Period] = CosinePart[Period] + CleanedData[CurrentBar-n]*cos(DegreesToRadians(360*n/Period)); SinePart[Period] = SinePart[Period] + CleanedData[CurrentBar-n]*sin(DegreesToRadians(360*n/Period)); } Pwr[Period] = CosinePart[Period]*CosinePart[Period] + SinePart[Period]*SinePart[Period]; } // Find Maximum Power Level for Normalization MaxPwr = Pwr[8]; for(Period=8; Period<=50; Period++) { if(Pwr[Period] > MaxPwr) MaxPwr = Pwr[Period]; } // Normalize Power Levels and Convert to Decibels for(Period=8; Period<=50; Period++) { if(MaxPwr > 0 && Pwr[Period] > 0) { DB[Period] = -10*log(.01 / (1-.99*Pwr[Period]/MaxPwr))/log(10); if(DB[Period] > 20) DB[Period] = 20; } } // Find Dominant Cycle using CG algorithm Num=0; Denom=0; for(Period=8; Period<=50; Period++) { if(DB[Period] < 3) { Num = Num + Period*(3-DB[Period]); Denom = Denom + (3-DB[Period]); } } if(Denom != 0) { DominantCycle = Num/Denom; pResults[CurrentBar].dValue = DominantCycle; } else { pResults[CurrentBar].dValue = 0; } pResults[CurrentBar].chIsValid = 'Y'; } free(Price); free(HP); free(CleanedData); return 0; }--Pete Rast
Avarin Systems, Inc.
www.StrataSearch.com
MULTICHARTS: Fourier Transform For Traders
As our users know, MultiCharts' scripting language is fully compatible with EasyLanguage. This means that you can use the TradeStation code for John Ehlers' techniques right from sidebar in the article "Fourier Transform For Traders" in this issue. The result of applying the transformed DTF indicator as described by Ehlers to MultiCharts is demonstrated in Figure 8.
FIGURE 8: MULTICHARTS, TRANSFORMED DTF. On this chart of the S&P emini continuous contracts, you can see how the indicator looks.
To discuss this article or download a copy of the formulas, please visit our discussion forum at forum.tssupport.com.--Stanley Miller
TS SUPPORT, LLC
www.tssupport.com
AIQ: Entropic Analysis
For this Traders' Tip, we'll look back to the November 2006 issue of STOCKS & COMMODITIES and the article by Ron McEwan, "Entropic Analysis of Equity Prices."
To test the effectiveness of the entropic indicator, I devised two trading systems based on McEwan's suggestions as follows:
System 1 (test Eps1)
Enter a long position if:
1) Two days ago the entropic indicator is less than 50, and
2) Yesterday and today the entropic is greater than 50
Exit the long position if the entropic drops below 50 for two days.Reverse the rules for a short position (not tested).
System 2 (test Eps2)
McEwan suggests that the indicator can be used as a buy signal when it turns up from a low value and as a sell-short signal when it turns down from a high value. I tried the fixed values suggested but, on the NASDAQ 100 stocks, there were not enough trades during my test period. Instead of fixed values, I decided to put standard deviation bands around the indicator as overbought and oversold levels to trigger entries. I also added a trend filter so that the second system only trades in the direction of the intermediate trend. The rules follow:Enter a long position if:
1) The entropic crosses up from below a two standard deviation band based on a 20-day simple moving average of the indicator, and
2) The 50-day simple moving average of the NASDAQ 100 index is sloping upward based on a five-day linear regression line on the average.Exit the long position if:
1) The entropic indicator crosses above the upper standard deviation band set to two standard deviations from a 20-day simple moving average of the indicator, or
2) The five-day linear regression slope of the 50-day simple moving average of the NASDAQ 100 index is sloping downward.I used a 30-day relative strength (strongest first) to select the trades, taking two per day, and a maximum of 5 at 20% of the account balance each.
Enter a short position if:
1) The entropic crosses down from above a 2.5 standard deviation band based on a 20-day simple moving average of the indicator, and
2) The 50-day simple moving average of the NASDAQ 100 index is sloping downward based on a five-day linear regression line on the average.Exit the short position if:
1) The entropic indicator crosses below the upper standard deviation band set to two standard deviations from a 20-day simple moving average of the indicator, or
2) A profit protect set to 100% above 1% is violated, or
3) A stop-loss of 5% is violated, or
4) The five-day linear regression slope of the 50-day simple moving average of the NASDAQ 100 index is sloping downward.I used a 30-day relative strength (weakest first) to select the trades, taking two per day, and a maximum of 5 at 20% of the account balance each.
Both systems were tested over the period 10/30/1998 to 11/06/2007 using the NASDAQ 100 stock list. A comparison of the two systems, trading the long side, is shown in Figure 9. System 2 (test Eps2) is shown as the dark blue line and it outperforms system 1. System 1 shows a 58.5% maximum drawdown, which is much higher than the drawdown of 16.4% for system 2. In addition, the Sharpe ratio of 1.26 is better on system 2 versus system 1's Sharpe ratio of 0.76. The short side on system 2 was tested and it turned out to have a consistent, downward-sloping equity curve (not shown), losing 24% over the test period (annualized loss of 3.4%) with a Sharpe ratio of -1.25. The rate of loss is not large enough to make it worth trying to trade the short side in reverse.
FIGURE 9: AIQ, ENTROPIC ANALYSIS. Here are the equity curves that compare trading the long side only for two trading systems using the entropic indicator to generate signals on NASDAQ 100 stocks.The AIQ code for the entropic indicator and related trading systems can be downloaded from the AIQ website at https://www.aiqsystems.com/S&C1.htm.
!! ENTROPIC ANALYSIS OF EQUITY PRICES ! Author: Ron McEwan TASC Nov 2006 p. 56 ! Coded by: Richard Denning 10/30/06 N is 30. C is [close]. C1 is val([close],1). EMA20 is expavg(C,20). SMA50 is simpleavg(C,50). LnRC1 is ln(C / C1). SMAn is simpleavg(LnRC1,N). RMS is sqrt((sum(LnRC1 * LnRC1,N)) / N). EP is (((SMAn / RMS) + 1) / 2) * 100. !! SYSTEM 1: ! Long if above 50 for 2 day , exit long if less than or equal to 50 LE if countof(EP > 50,2)=2 and countof(EP > 50,10,2)=0 and slope2(EMA20,5)>0 and hasdatafor(100)>=60. LX if countof(EP <= 50,2)=2. !! SYSTEM 2: ! Set parameters for bands on EP: Define L 20. Define Factor1 2. Define Factor2 2.5. ! Standard Deviation of EP: Variance is Variance(EP,L). StdDev is Sqrt(Variance). ! Middle EP Band SMA is simpleavg(EP,L). ! Upper EP Bands UpperEP1 is SMA + Factor1 * StdDev. UpperEP2 is SMA + Factor2 * StdDev. ! Lower EP Bands LowerEP1 is SMA - Factor1 * StdDev. LowerEP2 is SMA - Factor2 * StdDev. ! Use bands on the EP indicatior to generate signals: LE1 if EP > LowerEP1 and valrule(EP < LowerEP1,1) and TickerRule("NDX",slope2(SMA50,5)>0) and hasdatafor(100)>=60. LX1 if EP > UpperEP1 or slope2(SMA50,5)<0. SE1 if EP < UpperEP2 and valrule(EP > UpperEP2,1) and TickerRule("NDX",slope2(SMA50,5)<0) and hasdatafor(100)>=60. SX1 if EP <LowerEP1 or slope2(SMA50,5)>0.
--Richard Denning
AIQ Systems
richard.denning@earthlink.net
VT TRADER: Going Beyond 70 and 30 In Forex
For this month's Traders Tip, we'd like to revisit the August 2006 issue of STOCKS & COMMODITIES. The Forex Focus section in that issue outlined a trading system using the RSI and ATR indicators, which, according to the article's author Jamie Saettele, tested profitably on intraday intervals: the one-hour interval and the four-hour interval.
We'll be offering this trading system as well as a description of its logic for download in our user forums. The VT Trader code and instructions for creating the RSI/ATR trading system will be found there as well as shown here. The input variables are parameterized to allow customization.
A sample chart is shown in Figure 10. To learn more about VT Trader, visit www.cmsfx.com.
FIGURE 10: VT TRADER, RSI/ATR TRADING SYSTEM. Here is Jamie Saettele's RSI/ATR trading system on a one-hour candlestick chart of the USD/CHF.1. Navigator Window>Tools>Trading Systems Builder>[New] button 2. In the Indicator Bookmark, type the following text for each field: Name: TASC - 08/2006 - "Going Beyond 70 and 30 In Forex" Short Name: TASC_082006_RSI_TS_01 Label Mask: TASC - 08/2006 - "Going Beyond 70 and 30 In Forex" (ATR(%atrperiods%), RSI(%rsipr%,%rsitpr%), %% of ATR Levels: %atrel%, %atrsl%) 3. In the Input Bookmark, create the following variables: [New] button... Name: atrperiods , Display Name: ATR Periods , Type: integer , Default: 21 [New] button... Name: rsipr , Display Name: RSI Price , Type: price , Default: close [New] button... Name: rsitpr , Display Name: RSI Periods , Type: integer , Default: 21 [New] button... Name: atrel , Display Name: % of ATR for Entry Level , Type: float , Default: 0.1500 [New] button... Name: atrsl , Display Name: % of ATR for Stoploss Level , Type: float , Default: 0.3000 4. In the Formula Bookmark, copy and paste the following formula: {Provided By: Visual Trading Systems, LLC (c) Copyright 2007} {Description: Going Beyond 70 and 30 In Forex - Trading System} {Notes: August 2006 Issue ? Going Beyond 70 and 30 In Forex by Jamie Saettele} {TASC_082006_RSI_TS_01 Version 1.0} {Control Error} Barnum:= BarCount(); {ATR Indicator} _ATR:= ATR(atrperiods); {Relative Strength Index} rsi_r:= (rsipr - ref(rsipr,-1)); rsi_rs:= Wilders(if(rsi_r>0,rsi_r,0),rsitpr) / Wilders(if(rsi_r<0,Abs(rsi_r),0),rsitpr); RSIndex:= 100-(100/(1+rsi_rs)); RSIML:= 50; RSIUp:= 60; RSIDown:= 40; RSIOS:= 30; RSIOB:= 70; {1st Set of Entry/Exit Trade Signals} PreLongEntryCond1:= Cross(RSIndex,RSIML); PreLEC1High:= valuewhen(1,PreLongEntryCond1,H); PreLEC1EntryLevel:= PreLEC1High + PREC((valuewhen(1,PreLongEntryCond1,_ATR) * atrel),4); LongEntrySetup:= Cross(C,PreLEC1EntryLevel); LongExitSetup:= Cross(RSIML,RSIndex) OR Cross(RSIOB,RSIndex); LongTradeSetup:= If(PREV=NULL,LongEntrySetup, ref(barssince(PreLEC1EntryLevel<>ref(PreLEC1EntryLevel, -1))<barssince(LongEntrySetup),-1) and LongEntrySetup); LongEntrySignal:= Long2TradeAlert=0 AND Cross(LongTradeSetup,0.5); LongEntryPrice:= valuewhen(1,LongEntrySignal,C); LongEntryInitialStop:= if(LongTradeAlert=1 OR LongEntrySignal OR LongExitSignal, valuewhen(1,LongEntrySignal,PreLEC1EntryLevel) - PREC((valuewhen(1,LongEntrySignal,_ATR) * atrsl),4), null); LongExitSignal:= LongTradeAlert=1 AND (LongExitSetup OR Cross(LongEntryInitialStop,C)); LongExitPrice:= valuewhen(1,LongExitSignal,C); LongTradeAlert:= SignalFlag(LongEntrySignal,LongExitSignal); {----} PreShortEntryCond1:= Cross(RSIML,RSIndex); PreSEC1Low:= valuewhen(1,PreShortEntryCond1,L); PreSEC1EntryLevel:= PreSEC1Low - PREC((valuewhen(1,PreShortEntryCond1,_ATR) * atrel),4); ShortEntrySetup:= Cross(PreSEC1EntryLevel,C); ShortExitSetup:= Cross(RSIndex,RSIML) OR Cross(RSIndex,RSIOS); ShortTradeSetup:= If(PREV=NULL,ShortEntrySetup, ref(barssince(PreSEC1EntryLevel<>ref(PreSEC1EntryLevel, -1))<barssince(ShortEntrySetup),-1) and ShortEntrySetup); ShortEntrySignal:= Short2TradeAlert=0 AND Cross(ShortTradeSetup,0.5); ShortEntryPrice:= valuewhen(1,ShortEntrySignal,C); ShortEntryInitialStop:= if(ShortTradeAlert=1 OR ShortEntrySignal OR ShortExitSignal, valuewhen(1,ShortEntrySignal,PreSEC1EntryLevel) + PREC((valuewhen(1,ShortEntrySignal,_ATR) * atrsl),4), null); ShortExitSignal:= ShortTradeAlert=1 AND (ShortExitSetup OR Cross(C,ShortEntryInitialStop)); ShortExitPrice:= valuewhen(1,ShortExitSignal,C); ShortTradeAlert:= SignalFlag(ShortEntrySignal,ShortExitSignal); {***********************************************} {2nd Set of Entry/Exit Signals} Long2EntrySetup:= (LongTradeAlert=1 OR Cross(LongTradeAlert,0.5)) AND Cross(RSIndex,RSIUp); Long2ExitSetup:= Cross(ShortEntrySignal,0.5) OR Cross(RSIDown,RSIndex); Long2EntrySignal:= Long2TradeAlert=0 AND Long2EntrySetup; Long2ExitSignal:= (Long2TradeAlert=1 AND Long2ExitSetup) OR (Long2TradeAlert=1 AND Cross(ShortTradeSetup,0.5)); Long2TradeAlert:= SignalFlag(Long2EntrySignal,Long2ExitSignal); Long2EntryPrice:= valuewhen(1,Long2EntrySignal,C); Long2ExitPrice:= valuewhen(1,Long2ExitSignal,C); {----} Short2EntrySetup:= (ShortTradeAlert=1 OR Cross(ShortTradeAlert,0.5)) AND Cross(RSIDown,RSIndex); Short2ExitSetup:= Cross(LongEntrySignal,0.5) OR Cross(RSIndex,RSIUp); Short2EntrySignal:= Short2TradeAlert=0 AND Short2EntrySetup; Short2ExitSignal:= (Short2TradeAlert=1 AND Short2ExitSetup) OR (Short2TradeAlert=1 AND Cross(LongTradeSetup,0.5)); Short2TradeAlert:= SignalFlag(Short2EntrySignal,Short2ExitSignal); Short2EntryPrice:= valuewhen(1,Short2EntrySignal,C); Short2ExitPrice:= valuewhen(1,Short2ExitSignal,C); {***********************************************} {1st Set of Auto-Trading Variables} OpenBuy:= LongEntrySignal and (eventCount('OpenBuy')=eventCount('CloseBuy')); CloseBuy:= LongExitSignal and (eventCount('OpenBuy')>eventCount('CloseBuy')); OpenSell:= ShortEntrySignal and (eventCount('OpenSell')=eventCount('CloseSell')); CloseSell:= ShortExitSignal and (eventCount('OpenSell')>eventCount('CloseSell')); {2nd Set of Auto-Trading Variables} OpenBuy2:= Long2EntrySignal and (eventCount('OpenBuy2')=eventCount('CloseBuy2')); CloseBuy2:= Long2ExitSignal and (eventCount('OpenBuy2')>eventCount('CloseBuy2')); OpenSell2:= Short2EntrySignal and (eventCount('OpenSell2')=eventCount('CloseSell2')); CloseSell2:= Short2ExitSignal and (eventCount('OpenSell2')>eventCount('CloseSell2')); 5. In the Output Bookmark, create the following variables: [New] button... Var Name: _ATR Name: ATR * Checkmark: Indicator Output Select Indicator Output Bookmark Color: blue Line Width: slightly thicker Line Style: solid Placement: Additional Frame 1 [OK] button... [New] button... Var Name: RSIndex Name: RSI * Checkmark: Indicator Output Select Indicator Output Bookmark Color: dark green Line Width: slightly thicker Line Style: solid Placement: Additional Frame 2 [OK] button... [New] button... Var Name: RSIOB Name: RSI OverBought Level * Checkmark: Indicator Output Select Indicator Output Bookmark Color: red Line Width: thin Line Style: dashed Placement: Additional Frame 2 [OK] button... [New] button... Var Name: RSIUp Name: RSI Up Level * Checkmark: Indicator Output Select Indicator Output Bookmark Color: grey Line Width: thin Line Style: dashed Placement: Additional Frame 2 [OK] button... [New] button... Var Name: RSIML Name: RSI Middle Level * Checkmark: Indicator Output Select Indicator Output Bookmark Color: grey Line Width: thin Line Style: dashed Placement: Additional Frame 2 [OK] button... [New] button... Var Name: RSIDown Name: RSI Down Level * Checkmark: Indicator Output Select Indicator Output Bookmark Color: grey Line Width: thin Line Style: dashed Placement: Additional Frame 2 [OK] button... [New] button... Var Name: RSIOS Name: RSI OverSold Level * Checkmark: Indicator Output Select Indicator Output Bookmark Color: red Line Width: thin Line Style: dashed Placement: Additional Frame 2 [OK] button... [New] button... Var Name: LongEntryInitialStop Name: Long Entry Initial Stoploss * Checkmark: Indicator Output Select Indicator Output Bookmark Color: blue Line Width: thin Line Style: dashed Placement: Price Frame [OK] button... [New] button... Var Name: ShortEntryInitialStop Name: Short Entry Initial Stoploss * Checkmark: Indicator Output Select Indicator Output Bookmark Color: red Line Width: thin Line Style: dashed Placement: Price Frame [OK] button... [New] button... Var Name: LongEntrySignal Name: LongEntrySignal Description: Long Entry Signal Alert * Checkmark: Graphic Enabled * Checkmark: Alerts Enabled Select Graphic Bookmark Font [...]: Up Arrow Size: Medium Color: Blue Symbol Position: Below price plot Select Alerts Bookmark Alerts Message: Long Entry Signal! Choose sound for audible alert [OK] button... [New] button... Var Name: LongExitSignal Name: LongExitSignal Description: Long Exit Signal Alert * Checkmark: Graphic Enabled * Checkmark: Alerts Enabled Select Graphic Bookmark Font [...]: Exit Sign Size: Medium Color: Blue Symbol Position: Above price plot Select Alerts Bookmark Alerts Message: Long Exit Signal! Choose sound for audible alert [OK] button... [New] button... Var Name: ShortEntrySignal Name: ShortEntrySignal Description: Short Entry Signal Alert * Checkmark: Graphic Enabled * Checkmark: Alerts Enabled Select Graphic Bookmark Font [...]: Down Arrow Size: Medium Color: Red Symbol Position: Above price plot Select Alerts Bookmark Alerts Message: Short Entry Signal! Choose sound for audible alert [OK] button... [New] button... Var Name: ShortExitSignal Name: ShortExitSignal Description: Short Exit Signal Alert * Checkmark: Graphic Enabled * Checkmark: Alerts Enabled Select Graphic Bookmark Font [...]: Exit Sign Size: Medium Color: Red Symbol Position: Below price plot Select Alerts Bookmark Alerts Message: Short Exit Signal! Choose sound for audible alert [OK] button... [New] button... Var Name: Long2EntrySignal Name: Long2EntrySignal Description: Long Entry Signal 2 Alert * Checkmark: Graphic Enabled Select Graphic Bookmark Font [...]: Up Arrow Size: Small Color: Dark Blue Symbol Position: Below price plot [OK] button... [New] button... Var Name: Long2ExitSignal Name: Long2ExitSignal Description: Long Exit Signal 2 Alert * Checkmark: Graphic Enabled Select Graphic Bookmark Font [...]: Exit Sign Size: Small Color: Dark Blue Symbol Position: Above price plot [OK] button... [New] button... Var Name: Short2EntrySignal Name: Short2EntrySignal Description: Short Entry Signal 2 Alert * Checkmark: Graphic Enabled Select Graphic Bookmark Font [...]: Down Arrow Size: Small Color: Dark Red Symbol Position: Above price plot [OK] button... [New] button... Var Name: Short2ExitSignal Name: Short2ExitSignal Description: Short Exit Signal 2 Alert * Checkmark: Graphic Enabled Select Graphic Bookmark Font [...]: Exit Sign Size: Small Color: Dark Red Symbol Position: Below price plot [OK] button... [New] button... Var Name: OpenBuy Name: OpenBuy Description: Automated Open Buy Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Buy Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: CloseBuy Name: CloseBuy Description: Automated Close Buy Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Sell Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: OpenSell Name: OpenSell Description: Automated Open Sell Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Sell Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: CloseSell Name: CloseSell Description: Automated Close Sell Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Buy Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: OpenBuy2 Name: OpenBuy2 Description: Automated Open Buy 2 Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Buy Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: CloseBuy2 Name: CloseBuy2 Description: Automated Close Buy 2 Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Sell Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: OpenSell2 Name: OpenSell2 Description: Automated Open Sell 2 Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Sell Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... [New] button... Var Name: CloseSell2 Name: CloseSell2 Description: Automated Close Sell 2 Trade Command * Checkmark: Trading Enabled Select Trading Bookmark Trade Action: Buy Traders Range: 5 Hedge: no checkmark EachTick Count: 1 [OK] button... 6. Click the "Save" icon to finish building this trading system. To attach this trading system to a chart right-click with the mouse within the chart window, select "Add Trading System" -> TASC - 08/2006 - "Going Beyond 70 and 30 In Forex" from the list. Once attached to the chart the parameters can be customized by right-clicking with the mouse over the displayed trading system label and selecting "Edit Trading Systems Properties".
GO BACK
Return to January 2007 Contents
Originally published in the January 2007 issue of Technical Analysis of STOCKS & COMMODITIES magazine.
All rights reserved. © Copyright 2006, Technical Analysis, Inc.