October 2001
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 issue.

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 EASYLANGUAGE: TREND DETECTION INDEX
TRADESTATION EASYLANGUAGE: MONEY MANAGEMENT INDICATORS
NEUROSHELL TRADER: MONEY MANAGEMENT INDICATORS
WEALTH-LAB: MONEY MANAGEMENT INDICATORS
WAVE WI$E MARKET SPREADSHEET

or return to October 2001 Contents


TRADESTATION EASYLANGUAGE: TREND DETECTION INDEX

In my article in this issue, I present the trend detection index (TDI), which can be used to help detect when a trend has begun and when it has come to an end. Here's how to calculate the TDI in TradeStation EasyLanguage:

 
inputs:
 Price( Close ),
 Length( 20 ) ;

variables:
 Length2( 2 * Length ),
 Mom( 0 ),
 MomAbs( 0 ),
 MomSum( 0 ),
 MomSumAbs( 0 ),
 MomAbsSum( 0 ) ,
 MomAbsSum2( 0 ),
 TDL( 0 ),
 MktPos( 0 ) ;

Mom = Price - Price[Length] ;
MomAbs = AbsValue( Mom ) ;
MomSum = Summation( Mom, Length ) ;
MomSumAbs = AbsValue( MomSum ) ;
MomAbsSum = Summation( MomAbs, Length ) ;
MomAbsSum2 = Summation( MomAbs, Length2 ) ;
{Plot TDL for the index itself.}
TDL = MomSumAbs - ( MomAbsSum2 - MomAbsSum ) ;
{Plot MktPos for outright buy and sell signals}
MktPos = Iff( TDL[1] > 0, Iff( MomSum[1] > 0, 1, -1 ), MktPos[1] );
Plot1( MktPos,"Position");

--M.H. Pee
GO BACK


TRADESTATION EASYLANGUAGE:  MONEY MANAGEMENT INDICATORS

The EasyLanguage code for the average trade P/L indicator described in my article, "Money Management Indicators," is shown here. It consists of two parts: function AveTradeMA, which returns the average normalized trade profit/loss and the t statistic through its argument list; and second, the code for the indicator, which calls AveTradeMA.

 
{
Function: AveTradeMA ("Average Trade Moving Average")
Calculate the average of the last N trades.
Also, calculate the t statistic between the average and the input population average. Return both the average and the t statistic through the argument list. The average is normalized by the average true range of the last N bars.

Calls: I_ClosedEquity ( built-in function)
 Average_a(StdDevArray, Array_Size) ( built-in function)
 StdDevS_a(StdDevArray, Array_Size) ( built-in function)
 SquareRoot ( built-in function)

by Michael R. Bryant, Breakout Futures, www.BreakoutFutures.com
}

Input: AveTrade (NumericRef), {average of last N trades, normalized}
 PopAve (NumericSimple), {population average normalized win}
 tstat (NumericRef), { t statistic }
 N (NumericSimple); {# trades for calculations }

Array: TradePL[300](0);  { Trade P/L sequence }

Var: NewTradePL (0), { profit/loss from latest closed trade }
 PrevEquity (0), { closed trade equity on previous bar }
 NTrades (0), { number of trades }
 StdDevTr (0), { standard deviation of trades }
 ATR (0), { average true range }
 ii (0); { loop counter }

{Calculate average true range to normalize avg trade by }
ATR = Average(TrueRange, N);

{ look for closed trade }
If AbsValue(I_ClosedEquity - PrevEquity) >= 0.01 then Begin { new trade }
 NewTradePL = (I_ClosedEquity - PrevEquity)/BigPointValue/ATR;

 NTrades = NTrades + 1;

 { Add new trade to array of trades }
 If NTrades > N then Begin
  For ii = 0 to N - 2 Begin   { shift trades down to make room }
   TradePL[ii] = TradePL[ii + 1];
  end;
  TradePL[N - 1] = NewTradePL;  { add new trade at end of array }
 end
 else
  TradePL[NTrades - 1] = NewTradePL;

 { Perform calculations when enough trades }
 If NTrades >= N then Begin
  AveTrade = Average_a(TradePL, N);
  StdDevTr = StdDevS_a(TradePL, N);

  { do t test for statistical significance }
  if StdDevTr > 0 then
   tstat = (AveTrade - PopAve)/(StdDevTr/SquareRoot(N))
  else
   tstat = 10;   { arbitrary large number to represent infinity }
 End;

End; { new trade }
PrevEquity = I_ClosedEquity;  { store current equity for next bar }

AveTradeMA = 1;
 

 The code for the average trade indicator is as follows:

{
Indicator: Ave Trade (MA)
This indicator plots the average of the last N trades.
The trades are normalized by the average true range over the last N bars.

Calls: AveTradeMA  (user function)

by Michael R. Bryant, Breakout Futures, www.BreakoutFutures.com
}

Input: PopAve (.50), { average normalized trade of population }
 tConf (2), { t statistic at desired confidence level }
 N (30); { size of window for calculating data }

Var: AveTrade (0), { average trade in N-size sample }
 tstat (0); { t statistic for significance test }

{ Calculate average of last N trades }
value1 = AveTradeMA(AveTrade, PopAve, tstat, N);

if AbsValue(tstat) >= tConf then
 SetPlotColor(1, Green)
else
 SetPlotColor(1, Red);

Plot1(AveTrade, "Ave Trade");
Plot2(tstat, "t-stat");
Plot3(0, "");
 
 

Similarly, the EasyLanguage code for the runs test indicator consists of one main function and the indicator code, which calls the function. Function RunsMA collects the data and calls function RunsZScore, which computes the z value for the runs test. The code for the indicator calls RunsMA.
 
{
Function: RunsMA ("Runs test moving average")
Perform a runs test on the last N trades.  The runs test indicates the probability that the number of runs of wins and losses is different than if the trades occurred in random order.  A positive dependency occurs if there are fewer runs than random, so that wins tend to follow wins and losses tend to follow losses. A negative dependency between trades occurs when there are more runs than random, so that losses tend to follow wins, and vice versa.
This function calculates the runs probability on each bar using the last N trades. The runs test calculations are performed by function RunsZScore.
 
Calls: RunsZScore (user function)
 I_ClosedEquity (built-in function)

Michael R. Bryant, Breakout Futures, www.BreakoutFutures.com
}

Input:  N (NumericSimple);  { look-back length; # trades for runs test }

Array:  BinPL[500] (0);    { binary P/L sequence (0, 1) }

Var: NTrades (0), { Number of trades }
 NewTradePL (0), { profit/loss from latest closed trade }
 NewBinPL (0), (0/1 value of NewTradePL; 0->loss, 1->profit}
 PrevEquity (0), { closed trade equity on previous bar }
 NRuns (0), { number of runs }
 NWins (0), { number of wins }
 ZProb (0), { probability result from runs test }
 RetValue (0), { return value }
 ii (0); { loop counter }

{ look for closed trade }
If AbsValue(I_ClosedEquity - PrevEquity) >= 0.01 then Begin { new trade }
 NewTradePL = I_ClosedEquity - PrevEquity;

 { Convert trade value to binary: 1-> profit; 0-> loss }
 If NewTradePL > 0 then
  NewBinPL = 1
 else
  NewBinPL = 0;

 NTrades = NTrades + 1;

 { Add new trade to array of binary trades }
 If NTrades > N then Begin
  For ii = 0 to N - 2 Begin { shift trades down to make room }
   BinPL[ii] = BinPL[ii + 1];
  end;
  BinPL[N - 1] = NewBinPL;  { add new trade at end of array }
 end
 else
  BinPL[NTrades - 1] = NewBinPL;

end; { new trade }

PrevEquity = I_ClosedEquity;  { store current equity for next bar }

{ Perform runs test when enough trades }
If NTrades >= N then Begin
 NRuns = 1;
 For ii = 1 to N - 1 Begin   { count runs }
  If BinPL[ii] <> BinPL[ii - 1] then
   NRuns = NRuns + 1;
 end;
 NWins = 0;
 For ii = 0 to N - 1 Begin   { add up number of wins }
  If BinPL[ii] > 0 then
   NWins = NWins + 1;
 end;

 { Call z-score statistical runs test function }
 ZProb = RunsZScore(N, NWins, NRuns);

 { Convert probability to [-1, +1] }
 If ZProb < 0 then
  ZProb = 100 + ZProb;
 RetValue = 1 - ZProb/50;

End; { If NTrades >= N }

RunsMA = RetValue;
 

{
Function RunsZScore
Returns probability that the number of runs in a sequence of trades is  different than if the trades occur in a random order. If the z-score is  negative, a negative probability is returned. If the z-score is positive, a positive probability is returned.
Uses statistical equation for runs test from "Money Management Strategies for Futures Traders" by Nauzer Balsara, John Wiley & Sons, 1992.

Calls: Built-in function NormalSCDensity(NStdDev), where NStdDev is the  number of standard deviations in the unit normal probability distribution curve.

Michael R. Bryant, Breakout Futures, www.BreakoutFutures.com
}

Input: NTrades (numericSimple), { total # of trades }
 NWins  (numericSimple), { # of winning trades, PL>0 }
 NRuns  (numericSimple); { number of runs }

Var: ZScore (0), { Z score (# std dev) }
 Xval (0), { intermediate calculation }
 Num (0), { numerator }
 Den (0), { denomenator }
 CumProb (0); { cumulative probability }

Xval = 2 * NWins * (NTrades - NWins)/NTrades;
Num = NRuns - (Xval + 1);
Den = power(((Xval * (Xval - 1))/(NTrades - 1)), 0.5);
ZScore = Num/Den;

CumProb = NormalSCDensity(ZScore);
If ZScore < 0 then
 RunsZScore = -100 * (1 - CumProb)
else
 RunsZScore = 100 * CumProb;
 

 Finally, the code for the runs test indicator is as follows:

{
Indicator: TradeDependency
This indicator calculates the runs probability on each bar using the last N trades. The runs test calculations are performed by function  RunsMA, which returns a value in the range -1 to +1. A value of -1 represents 100% probability that there is negative trade dependency, whereas a value of +1 indicates 100% probability of positive trade dependency.

Calls: RunsMA (user function)

by Michael R. Bryant, Breakout Futures, www.BreakoutFutures.com
}

Input: N (30), { look-back length; # trades for runs test }
 SigVal (0.9); { signficant value of runs test indicator }

Var: IndValue (0); { runs test indicator value to plot }

{ Perform runs test }
IndValue = RunsMA(N);

if AbsValue(IndValue) >= SigVal then
 SetPlotColor(1, Green)
else
 SetPlotColor(1, Red);

Plot1(IndValue, "Dependency");
Plot2(0, "Zero");

--Michael R. Bryant
GO BACK


NEUROSHELL TRADER: MONEY MANAGEMENT INDICATORS

In "Money Management Indicators" in this issue, Michael Bryant describes the average trade P/L indicator, which keeps track of the last N trades and displays the average profit or loss.

The first step to implementing the average trade P/L analysis in NeuroShell Trader is to create a NeuroShell Trading Strategy to which the analysis will be applied. You can use any Trading Strategy or Prediction that you have previously created using NeuroShell Trader, or you can create a new one. In all of the following indicators, you should simply substitute the name of your Trading Strategy or Prediction in place of "TradingStrategy."
 
 


 

Figure 1: NEUROSHELL TRADER. Here's
Michael Bryant's average trade P/L analysis as charted in NeuroShell Trader.

Once you have a Trading Strategy created, you can implement the average trade P/L indicator in NeuroShell Trader by first creating the three intermediate indicators TradePL, NormalizedTradePL, and NewTradeFlag before creating the final AveTrade indicator. Select "New Indicator É" from the Insert menu to create each of the following indicators using the Indicator Wizard:

TradePL:
Momentum ( NetProfit ( TradingStrategy ), 1 )

NormalizedTradePL:
Divide ( TradePL, Avg( TrueRange ( High, Low, Close ), 30 )

NewTradeFlag:
A=B( Momentum ( NumTrades ( TradingStrategy ), 1), 1)

AveTrade:
SelectiveAvg ( NormalizedTradePL, NewTradeFlag, 30 )
 

 To implement the average trade P/L significance test in NeuroShell Trader, first create the three intermediate indicators StdDevTr, PopAve, and Tstat before creating the final TstatSignificant indicator:

StdDevTr:
SelectiveStndDev ( NormalizedTradePL, NewTradeFlag, 30 )

PopAve:  (In case you want to calculate instead of using a constant value of 0.5)
Divide ( CumSum ( NormalizedTradePL, 0 ), NumTrades ( Trading Strategy ) )

Tstat:
Divide ( Sub ( AveTrade, PopAve ), Divide ( StdDevTr, SqrRt ( 30 ) ) )

TstatSignifcant:
A>=B ( Abs ( Tstat ), 2 )
 
 

To implement the Runs Test in NeuroShell Trader, first create the three intermediate indicators NumWins, NumRuns, and Xval before creating the final RunsZscore indicator:
 
NumWins:
SelectiveSum ( A>B( TradePL, 0 ), NewTraderFlag, 30 )

NumRuns:
Add2 ( SelectiveSum ( SelectiveRange ( A>B(TradePL,0), NewTradeFlag, 2), NewTradeFlag, 29), 1 )

Xval:
Divide ( Mult3 ( 2, NumWins, Sub ( 30, NumWins ) ), 30 )

RunsZscore:
Divide (Sub ( NumRuns, Add2 ( Xval, 1 ) ), SqrRt ( Divide ( Mult2 ( Xval, Sub ( Xval, 1 ) ), 29 ) )
 

In these indicators, note that the trades' lookback was assumed to be 30, and in some cases a 29 was used for the trades' lookback minus 1. To change the trades' lookback to a different number, simply change all the occurrences of 30 and 29 to a new lookback, N and N-1, respectively. Also note that the true range indicator is included in the NeuroShell Trader Advanced Indicator Set Add-on and is also available free for download from the Ward Systems Group free technical support website.

Users of NeuroShell Trader can go to the Stocks & Commodities section of the Ward Systems Group free technical support website to download an average trade P/L chart (Figure 1), which also contains the AveTrade, TstatSignificant, NumWins, NumRuns, and RunsZscore indicators saved as custom indicators in the Traders' Tips custom indicator category.

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


GO BACK


WEALTH-LAB: MONEY MANAGEMENT INDICATORS

In "Money Management Indicators" in this issue, author Michael Bryant performs analysis on the average position profit. Our WealthScript language provides position-management functions that allow you to implement these strategies at the Wealth-Lab.com website and on our Wealth-Lab Desktop product.

This script is integrated into a simple channel breakout system for illustration (Figure 2). Change the value of the Period variable to experiment with a different number of trades for the average profit calculation. The average trade profit is displayed in histogram form in the lower pane in Figure 2, along with average trade profit divided by average true range (ATR).
 
 

FIGURE 2: WEALTH-LAB. The average trade profit
is displayed in histogram form in the lower pane, along
with average trade profit divided by average true range (ATR).

 
{ Channel Breakout System }
for Bar := 4 to BarCount() - 1 do
begin
 if LastPositionActive() then
 begin
  if SellAtStop( Bar + 1, Lowest( Bar, #Low, 3 ), LastPosition() ) then
  SetPositionData( LastPosition, Bar + 1 ); {Remember the bar number
that we exited}
 end
 else
  BuyAtStop( Bar + 1, 5000, Highest( Bar, #High, 3 ) );
end;

Period := 5;
AvgTradeSeries := CreateSeries;
ProfitSeries := CreateSeries;
AvgTradeSeriesATR := CreateSeries;

{ Populate ProfitSeries with the profit of each trade }
for p := 0 to PositionCount - 1 do
 SetSeriesValue( p, ProfitSeries, PositionProfit( p ) );

{ Populate the Average Profit per Trade Series }
LastBarFilled := 0;
for p := 0 to PositionCount - 1 do
begin
 n := Trunc( GetPositionData( p ) );
 if n >= BarCount then
  n := BarCount - 1;
 if p >= Period then
  for Bar := n downto LastBarFilled do
  begin
   x := SMA( p, ProfitSeries, Period );
   SetSeriesValue( Bar, AvgTradeSeries, x );
   SetSeriesValue( Bar, AvgTradeSeriesATR, x / ATR( Bar, Period ) );
  end;
  LastBarFilled := n;
end;

{ Color Bars }
for Bar := 0 to BarCount - 1 do
 if GetSeriesValue( Bar, AvgTradeSeries ) < 0 then
  SetBarColor( AvgTradeSeries, Bar, #Red )
 else
  SetBarColor( AvgTradeSeries, Bar, #Green );

{ Plot }
HideVolume;
AvgTradePane := CreatePane( 200, false, true );
PlotSeries( AvgTradeSeries, AvgTradePane, #Olive, #Histogram );
PlotSeries( AvgTradeSeriesATR, AvgTradePane, #Black, #ThickHist );
DrawLabel( ÔAverage Profit of Last Ô + IntToStr( Period ) + Ô Trades',
AvgTradePane );

--Dion Kurczek, Wealth-Lab.com
773 883-9047, dionkk@ix.netcom.com
https://www.wealth-lab.com


GO BACK


WAVE WI$E MARKET SPREADSHEET
 

The following WaveWi$e formulas demonstrate how to calculate some of Michael Bryant's trading statistics. The formulas use a simple moving average crossover to generate trading signals.

 
A: DATE @TC2000(C:\TC2000V3\Data,#IBM,Internat Business Mach,DB)
B: HIGH
C: LOW
D: CLOSE
E: OPEN
F: VOL
G: Avg   @MAVG(CLOSE,30)
H: SigAvg1  @SIGNAL(CLOSE,BUY,CLOSE>=AVG,CLOSE<AVG)
I: SigAvg2
J: Equity  @EQUITY(SIGAVG1,SIGAVG2, LONG)
K: Trades @TRADE(SIGAVG1,SIGAVG2, LONG)
L: EqAvg  @MAVG(EQUITY,30)
M: TrCount   @COUNT(TRADES)
N: Win       @IF(TRADES>=0,TRADES); @COUNT(THISCOL)
O: Loss      @IF(TRADES<0,TRADES); @COUNT(THISCOL)
P: BarCount  @IF(SIGAVG1>0,@CUM(1))
Q: WinDays   @IF(TRADES>=0,BARCOUNT)
R: LossDays  @IF(TRADES<0,BARCOUNT)
  Ô ==========End Formulas
--Peter Di Girolamo
Jerome Technology, 908 369-7503
jtiware@aol.com, https://members.aol.com/jtiware
GO BACK


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


Return to October 2001 Contents