February 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:
 
OMEGA RESEARCH EASYLANGUAGE
METASTOCK
NEUROSHELL TRADER
BYTE INTO THE MARKET
INVESTOR/RT
TRADING SOLUTIONS
TECHNIFILTER PLUS
AIQ TRADINGEXPERT
HIGH PERCENTAGE TRADING SYSTEM CODE
MONTE CARLO SYSTEM

or return to February 2001 Contents


OMEGA RESEARCH EASYLANGUAGE

This month in Traders' Tips, we'll be buffing up your moving averages using the volume-weighting method presented in Buff Dormeier's article in this issue, "Buff Up Your Moving Averages." The weighting formula has been created as a function in EasyLanguage so that it can be referenced from any analysis technique or strategy. In addition, a simple two-line volume-weighted average indicator that references the function has also been included.

The name of the volume-weighted average function is "BuffAverage." The function has two inputs, price and length. The price input represents the price value upon which the average calculation is based. The length input represents the number of bars that are used in the calculation of the average. Here is the EasyLanguage for the function:

Name: BuffAverage
Type: Function

Inputs: Price(Numeric), Length(Numeric);
Variables: VolSum(0), Buff(0);
        
VolSum = Summation(Volume, Length);
Buff = 0;

If VolSum <> 0 Then Begin
    For value1 = 0 To Length - 1 Begin
        Buff = Buff + ((Price[value1] * Volume[value1]) / VolSum);
    End;
End;

BuffAverage = Buff;
The two-line volume-weighted average indicator for EasyLanguage is named Buff averages. This indicator has three inputs. The price input represents the price value upon which the average calculation is based. The FastAvg input represents the number of bars to use in the fast volume-weighted average calculation. The SlowAvg input represents the number of bars to use in the slow volume-weighted average calculation. A simple alert criteria has also been included to provide an alert when the two lines cross.

Below is the EasyLanguage for this indicator. The recommended properties for the indicator are presented after the EasyLanguage code.

Name: Buff Averages
Type: Indicator

Inputs: Price(Close), FastAvg(5), SlowAvg(20);

Plot1(BuffAverage(Price, FastAvg), "FastBuff");
Plot2(BuffAverage(Price, SlowAvg), "SlowBuff");

If Plot1 Crosses Above Plot2 Then
        Alert("Buff Averages Bullish Crossover.");
If Plot1 Crosses Below Plot2 Then
        Alert("Buff Averages Bearish Crossover.");

Chart style:
PlotName       Style       Weight
FastBuff       Line        Thinnest
SlowBuff       Line        Thinnest

Chart color:
PlotName       Color
FastBuff       Magenta
SlowBuff       Cyan

Scaling: Same as symbol.
The EasyLanguage code for the Buff average function and indicator are also available for download from the EasyLanguage portion of the support section at Omega Research's website. The name of the file is "BuffAvg.Els" for use in TradeStation and ProSuite 2000i.
--Gaston Sanchez, EasyLanguage Expert
Omega Research Inc., 800 422-8587, 305 270-1095
https://www.omegaresearch.com
GO BACK

METASTOCK

The Buff averages, as described by Buff Dormeier in his article "Buff Up Your Moving Averages" in this issue, can easily be recreated in MetaStock 6.52 or higher.

To recreate the indicator in MetaStock, select Indicator Builder from the Tools menu and click New. The formula can be written one of two ways:
 

1. X:=Input("Time Periods",1,500,25);
    Sum(V*C,X)/Sum(V,X)

2. X:=Input("Time Periods",1,500,25);
    Sum(V*C,X)/(Cum(V)-Ref(Cum(V),-X))

To plot it, locate Buff Averages in MetaStock's Indicator Quicklist.
--Cheryl C. Abram, Equis International, Inc.
https://www.equis.com
GO BACK

NEUROSHELL TRADER

Buff Dormeier's volume-weighted moving average is already a standard indicator in NeuroShell Trader (Figure 1). To insert it in a chart, NeuroShell Trader users need only select the indicator category called "Volume-weighted moving average" and then select the first indicator there, also called volume-weighted moving average. There are a total of 15 other related volume-weighted moving averages our users can try also.

FIGURE 1: NEUROSHELL. This shows the parameters of the volume-weighted moving average as it is built in NeuroShell Trader Professional.
Users of NeuroShell Trader Professional or DayTrader Professional will also want to optimize the periods in their volume-weighted moving average crossovers using the genetic algorithm optimizer. As an example, this trading strategy was applied to Microsoft during the period 9/30/98 to 11/6/00. Using the optimizer in NeuroShell Trader Professional, the trading strategy earned a return on trades of 146.3% compared to a 26.3% change in price (Figure 2).

FIGURE 2: NEUROSHELL. This shows the result of an optimized trading strategy that was built in NeuroShell Trader Professional based on crossovers of volume-weighted moving averages.


Users of NeuroShell Trader can go to the STOCKS & COMMODITIES section of the NeuroShell Trader free technical support website to download an example chart. For more information on NeuroShell Trader, visit www.NeuroShell.com.

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

BYTE INTO THE MARKET

Here's how to implement Buff Dormeier's Buff moving averages in Byte Into The Market (BITM).

The trading system showing the calculation of the volume-weighted moving average and based on crossovers of this moving average is shown in Figure 3. Testing the system on a portfolio (we call these a security group) can be done very easily. First, we described a security group of all the securities in the article's 12 subgroups (some of these tickers are no longer current).

FIGURE 3: BYTE INTO THE MARKET. Here's the calculation for the volume-weighted moving average in Byte Into The Market.


To build the security group, select "security groups" from the File menu to open the security groups dialog. Check the securities in the group, and then name and save the new group to disk. If you have no source for this data, you can get the free BITM Quote utility from our website to download free data from Yahoo!. We then "restricted data" in the BITM software to the securities in this main group.

After naming and saving the security group, just click the "Restrict Data To Group" button. When you are using BITM with this data restriction in effect, the program won't use or display for selection any other data, which makes specification of the 12 subgroups easier and allows you to more easily scroll through the securities (change securities) in the group, applying a chart layout you are using to examine the system to each ticker sequentially (for example, only the tickers in the group get placed into the layout as you cycle through securities with either your mousewheel or repetitive icon bar clicks).

We created a layout with the charted system and the two volume-weighted moving averages in one pane and the simple moving average (SMA) crossover system and the two SMAs in a second pane. This chart template (layout) is available for download from our website at https://www.tarnsoft.com/buff.zip.

FIGURE 4: BYTE INTO THE MARKET. Here's a trading system in Byte Into The Market based on Buff volume-weighted moving averages. The two volume-weighted moving averages are in one pane and the simple moving average (SMA) crossover system and the two Smas are in a second pane. This chart template is available for download from Tarn Software's website.
 

FIGURE 5: BYTE INTO THE MARKET. You can test the Buff trading system on your main security group by calling up the multiple security test setup dialog to set up the parameters of your test (Figure 6).


A chart created from this template is shown in Figure 4. To run a test on the main security group, right-click the colored status button for the charted trade system to display its context menu and select "Multiple security test" as shown in Figure 5. The multiple security test setup dialog then appears, where you can set your cash management (for example, no stops, no commission, constant-share trade amount) and the dates for the tests, as well as how you would like the results ranked. Click the "tag all" button to test all the securities in the 12 subgroups at once (since the security group data restriction means that these are the only securities BITM is currently using). Or you can specify any of the subgroups by clicking "Clear tags" and then checking the securities in the subgroup. Such a setup is shown in Figure 6 for the "S&P large cap," "Highest beta" subgroup. This subgroup can be saved to disk, so in the future you can easily recreate that particular subgroup's selections (load it from a disk file).

FIGURE 6: BYTE INTO THE MARKET. Select the parameters for your trading system test, including cash management, test dates, and how you want the results ranked. You can run the test against all the securities in your main portfolio or you can create a subgroup of stocks to test on.


This tip is also available at https://www.tarnsoft.com.

--Tom Kohl, Tarn Software, 303 794-4184
bitm@tarnsoft.com, https://www.tarnsoft.com
GO BACK

INVESTOR/RT

Here are the Investor/RT scan formulas for this month's Traders' Tips subject, Buff moving averages.

Buff averages are calculated in Real Time Language as follows:

SUM( CL*(VO/(VMA * n)) , n )
where:
CL is the last price
VO is the day volume
VMA is the volume moving average over n periods.
The entire expression is summed over n periods. Note the volume moving average (VMA) is multiplied by its period to obtain the total volume.
--Eric Hynniman
Linn Software, 800 546-6842
sales@linnsoft.com, https://www.linnsoft.com
GO BACK

TRADINGSOLUTIONS

TradingSolutions allows you to enter custom formulas as function definitions that you apply to any stock or data series in your portfolio. These functions can also be exported to be shared with other users.

The volume-weighted moving average presented in Buff Dormeier's article in this issue, "Buff Up Your Moving Averages," can be entered in TradingSolutions using the following formula:

Div ( Sum ( Mult ( Close, Volume ), Period ), Sum ( Volume, Period ) )
This function is available in a function file that can be downloaded from our website in the Solution Library section. It can then be imported into TradingSolutions using "Import functions..." from the File menu. A sample chart can be seen in Figure 7.

FIGURE 7: TRADING SOLUTIONS. Here's a sample chart of the Buff volume-weighted moving averages as implemented in TradingSolutions software.


To apply one of these imported functions to a stock or group of stocks, select "Add New Field..." from the context menu for the stock or group, select "Calculate a value...," then select the desired function from the "Traders' Tips functions" group.

--Gary Geniesse, TradingSolutions Project Lead
NeuroDimension, Inc.
800 634-3327, 352 377-5144
info@tradingsolutions.com
www.tradingsolutions.com
GO BACK

TECHNIFILTER PLUS

Here is the TechniFilter Plus formula that computes the volume-weighted moving average described in Buff Dormeier's article in this issue, "Buff Up Your Moving Averages." The formula uses the TechniFilter Plus F-modifier to compute this average.
Formula for a volume-weighted average
NAME: Buff_Avg
PARAMETERS: 10
FORMULA:   (C*V)F&1 / VF&1
Visit RTR's website at https://www.rtrsoftware.com to download this formula as well as program updates. Release 8.3 is available for download.
--Clay Burch, RTR Software
919 510-0608, E-mail: rtrsoft@aol.com
https://www.rtrsoftware.com
GO BACK

AIQ TRADINGEXPERT

Here is some EDS code for AIQ TradingExpert that implements the Buff moving averages, submitted by an AIQ TradingExpert user.
! Buff Moving Averages (BMAs)  
! AIQ EDS codes by Onnfoh Yu

Define Fast 5.
Define Slow 20.

VolumeSumFast is Sum([Volume], Fast).
VolumeSumSlow is Sum([Volume], Slow).
VolumePrice is [Close]*[Volume].

FastBMA is Sum(VolumePrice,5)/VolumeSumFast.
SlowBMA is Sum(VolumePrice,20)/VolumeSumSlow.
--Onnfoh Yu, AIQ TradingExpert user
GO BACK

HIGH PERCENTAGE TRADING SYSTEM CODE

The trading system used in my article in this issue, "Position Sizing With Monte Carlo Simulation," can be coded in TradeStation and other software as follows:
Input:  ASize   (30000),        { starting account size, $ }
                DDGoal  (50),   { max closed out trade drawdown, % }
                RiskPer (10),   { percentage risk per trade }
                NRand   (1000), { number of random sequences }
                EntFrac (0.75); { multiple of range for entry }

 Var:   EntPr   (0),    { Entry target price }
                XitPr   (0),    { mm stop exit price }
                TrRisk  (0);    { trade risk, $ }
 
TrRisk = 1000;
EntPr = H + EntFrac * (H - L);
If C > C[1] then
        Buy next bar at EntPr Stop;
        
Exitlong("MMStop") next bar at EntryPrice - TrRisk/BigPointValue stop;
If BarsSinceEntry >= 1 and open of next bar > EntryPrice then
        ExitLong("ProfOpen") next bar at market;

Value1 = MonteCarlo (ASize, DDGoal, RiskPer, TrRisk, NRand);

{This last line calls the MonteCarlo function, which randomizes the trades and
summarizes the results. Delete it if you don't want the MonteCarlo results.}
--Michael R. Bryant
GO BACK

MONTE CARLO SYSTEM

The EasyLanguage 2000i function named MonteCarlo, which was referred to in my article in this issue, "Position Sizing With Monte Carlo Simulation," uses a Monte Carlo simulation to estimate the probability that a series of trades will produce a specified, maximum closed-trade drawdown. It consists of the following steps:

Collect the profit/loss for each trade and the amount risked on each trade. After all trades are collected, loop over the number of random sequences:

A. Generate a random sequence of the given trades.
B. Accumulate the account equity and calculate the maximum drawdown and rate of return for the current sequence.
C. Increment sums for the average return and the probability of meeting the drawdown goal.
Divide the sums from C by the number of sequences to obtain the average return and the drawdown probability.

The function uses the built-in parameter TotalTrades to determine when each trade exits. When TotalTrades changes value, it indicates that the prior trade has exited, and the profit/loss for that trade is collected in an array. In certain cases, it is possible for TotalTrades to increment by 2 on the current bar; in this case, the profit/loss from the last two trades are recorded on the same bar.

Once all the trade data have been collected in arrays, the function waits until the end of the chart before starting the calculations. Because the trading system looks forward one day (at the next day's opening), it never reaches the last bar on the chart. As a result, it is necessary to execute the calculations on the next-to-last, rather than the last, bar on the chart. This is the purpose of the line that contains the function LastCalcDate.

A random sequence of trades is generated by first collecting a series of M random numbers in an array, where M is the number of trades. Then the array of random number is sorted, and the order of the sorted array is taken as the sequence of the trades.

When calculating the rate of return and drawdown for each sequence, the number of contracts is calculated according to:

N = Risk%/100 * Equity/TradeRisk
where Risk% is the fixed fraction in percent (that is, percent of account risked on each trade), Equity is the current equity in the account up to that point, and TradeRisk is the dollar amount being risked on the next trade. Because the number of contracts must be a whole number, N is rounded down to the nearest integer. The number of contracts is then multiplied by the trade profit/loss and added to the current equity to get the new equity value.

The EasyLanguage 2000i code for function MonteCarlo follows:

Input: ASize (NumericSimple),          { account size, $ }
             DDGoal  (NumericSimple),  { max closed out trade drawdown, % }
             RiskPer (NumericSimple),  { percentage risk per trade }
             TrRisk  (NumericSeries),  { risk for current trade, $ }
             NRand   (NumericSimple);  { number of random sequences }

 Array:      Trades[200](0),     { Trades, $ (win +; loss -) }
             TrRisks[200](0),    { trade risks, $ (+) }
             RandNums[200](0),   { array of random numbers }
             RandIndx[200](-1);  { randomly chosen indices for trade array }

 Var:  NTrades (0),  { Number of trades } 
       iSeq    (0),  { sequence number }
       MaxNum  (0),  { max number left in array RandNums } 
       iMax    (0),  { index (location) of MaxNum in array RandNums }
       NCon    (0),  { number of contracts }
       Equity  (0),  { account equity }
       NewEquity (0),  { account equity }
       EqtyHigh  (0),  { highest equity }
       DD      (0),  { closed trade drawdown }
       DDmax   (0),  { worst case closed trade drawdown }
       PReturn (0),  { percent return }
       AveRet  (0),  { average percent return }
       ProbDD  (0),  { probability of drawdown goal }
       ii      (0),  { loop counter }
       jj      (0);  { loop counter }

 { Collect profit/loss and risk }
 If TotalTrades > NTrades then Begin
    If TotalTrades - NTrades < 2 then Begin
        NTrades = NTrades + 1;
        Trades[NTrades - 1] = PositionProfit(1);
        TrRisks[NTrades - 1] = TrRisk;
    end
    else Begin  { case where TotalTrades increments by 2 }
        NTrades = NTrades + 1;
        Trades[NTrades - 1] = PositionProfit(2);
        TrRisks[NTrades - 1] = TrRisk[1];
        NTrades = NTrades + 1;
        Trades[NTrades - 1] = PositionProfit(1);
        TrRisks[NTrades - 1] = TrRisk;
    end;
 end;

 { Calculate results 1 day from last bar on chart }
If Date = JulianToDate(DateToJulian(LastCalcDate) - 1) then Begin

    for iSeq = 1 to NRand Begin   { loop over # of random sequences }

        { Generate random sequence of trades }
        For ii = 0 to NTrades - 1 Begin { generate random numbers }
            RandNums[ii] = IntPortion(NTrades * Random(10));        
        end;
        For ii = 0 to NTrades - 1 Begin   { sort index of RandNums array }
            MaxNum = -1;
            For jj = 0 to NTrades - 1 Begin   { find biggest # left }
                If RandNums[jj] > MaxNum then Begin
                    MaxNum = RandNums[jj];
                    iMax = jj;
                end;
            end;
            RandIndx[ii] = iMax;   { record location of max number }
            RandNums[iMax] = -1;   { "remove" max # from array }
        end;

        { Calculate account balance and drawdown for current sequence }
        Equity = ASize;
        EqtyHigh = Equity;
        DDmax = 0;
        For ii = 0 to NTrades - 1 Begin
            NCon = IntPortion(RiskPer/100 * Equity/TrRisks[RandIndx[ii]]);
            NewEquity = Equity + NCon * Trades[RandIndx[ii]];

            { Calculate closed trade percent drawdown }
            If (NewEquity > EqtyHigh) then
                EqtyHigh = NewEquity
            else Begin
                DD = 100 * (EqtyHigh - NewEquity)/EqtyHigh;
                if (DD > DDmax) then
                    DDmax = DD;
            end;
            Equity = NewEquity;
        end; { for ii }
            PReturn = 100 * (Equity - ASize)/ASize;

            { Accumulate results for probability calculations }
            AveRet = AveRet + PReturn;
            if (DDmax <= DDGoal) then
                ProbDD = ProbDD + 1;
    End; { for iSeq }

    { Calculate probabilities by dividing sums by number of sequences }
    AveRet = AveRet/NRand;
    ProbDD = 100 * ProbDD/NRand;
    MessageLog("RiskPer=", RiskPer:5:1, "  DDGoal=", DDGoal:5:1,
        "  ProbDD=",ProbDD:5:1);
    MessageLog("Average Return = ", AveRet:6:2);
end;

MonteCarlo = 1;
--Michael R. Bryant
310 370-4069
GO BACK

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

Return to February 2001 Contents