October 2004
TRADERS' TIPS

Here is this month's selection of Traders' Tips, contributed by various developers of technical analysis software to help readers more easily implement some of the strategies presented in this and other issues.

You can copy these formulas and programs for easy use in your spreadsheet or analysis software. Simply "select" the desired text by highlighting as you would in any word processing program, then use your standard key command for copy or choose "copy" from the browser menu. The copied text can then be "pasted" into any open spreadsheet or other software by selecting an insertion point and executing a paste command. By toggling back and forth between an application window and the open Web page, data can be transferred with ease.

This month's tips include formulas and programs for:

  TRADESTATION: Fibonacci And Gann Projections
  AMIBROKER: Fibonacci And Gann Projections
  WEALTH-LAB: Fibonacci And Gann Projections
  eSIGNAL: Fibonacci And Gann Projections
  NEUROSHELL TRADER: Fibonacci And Gann Projections
  NEOTICKER: Fibonacci And Gann Projections
  PROPHET.NET: Fibonacci And Gann Projections
  SMARTRADER: Crack Spread
or return to October 2004 Contents


TRADESTATION: Fibonacci And Gann Projections

Dennis Peterson's article in this issue, "Fibonacci And Gann Projections," presents a technique for forecasting time and price turning points. The article discusses a "replay" style of chart reading. Thus, the TradeStation EasyLanguage code presented here discusses a procedure for "replaying" a chart in TradeStation.

The indicator provided here, "SqOf9_FibTimeComment," uses trendlines to mark forecasted price and time turning points, in accordance with the methodology described in Peterson's article. There needs to be ample chart space to the right of the chart's last bar for the code to work correctly. This extra space can be created by formatting the chart window and setting the "Space to the right" option. In this example, 30 bars were used for this setting. The number of bars required is established by the longest "zigzag" cycle, so every chart may require a different setting.

TradeStation's commentary feature can be used to "replay" the history of time/price forecasts made by the indicators. First, select a chart window so that it is the active window. Next, set the pointer tracking to "Window." Then activate the commentary feature by clicking the commentary icon (on the default "Chart Analysis" toolbar) then clicking somewhere in the chart window. A bar-by-bar replay can be performed by clicking on the bar for which the "replay" is desired to begin (with the analysis commentary pointer active) and then scrolling the chart, bar by bar, to the right using the right arrow key on the keyboard. The forecasts that would have been seen on that historical bar are displayed as the cursor is scrolled to the right using the right arrow key. (The commentary window that appears may be disregarded.) If the commentary feature is not activated, only the zigzags will be displayed on the chart; the forecasted turning points will not appear. A sample chart can be seen in Figure 1.

Figure 1: TRADESTATION, Fibonacci And Gann Projections. Here is a sample chart showing the SqOf9_FibTimeComment indicator on Intel. TradeStation's commentary feature can be used to "replay" the history of time/price forecasts made by the indicators.


An .ELD file including the EasyLanguage code will be posted in the file library at TradeStationWorld.com. Look for the file "SqOf9_FibTimeCommentary.Eld."
 

Function:  TimeForecast
inputs:
 PresentDate( NumericSimple ) ,
 PresentTime( NumericSimple ) ,
 DaysAhead( NumericSimple ) ,
 HoursAhead( NumericSimple ) ,
 MinutesAhead( NumericSimple ) ,
 oFutureDate( NumericRef ) ,
 oFutureTime( NumericRef ) ;
 
variables:
 DateTime( 0 ) ,
 FutureDateTime( 0 ) ;
DateTime = DateToJulian( PresentDate ) +
 ( TimeToMinutes( PresentTime ) / 60 / 24 ) ;
FutureDateTime = DateTime + DaysAhead + ( HoursAhead /
 24 ) + ( MinutesAhead / 60 / 24 ) ;
if DayOfWeekFromDateTime( FutureDateTime ) = Saturday
 then
  FutureDateTime = FutureDateTime - 1
else if DayOfWeekFromDateTime( FutureDateTime ) = Sunday
 then
 FutureDateTime = FutureDateTime + 1 ;
oFutureDate = JulianToDate( IntPortion(
 FutureDateTime ) ) ;
oFutureTime = MinutesToTime( FracPortion(
 FutureDateTime ) * 60 * 24 ) ;
TimeForecast = FutureDateTime ;
Function: FibTimeForecasts
inputs:
 PivotValues[ MaxSize1, MaxSize2 ]( NumericArray ),
 { ZigZagPivots[Row1-6, 1] = price }
 { ZigZagPivots[Row1-6, 2] = date }
 FibDateTime[MaxSize3]( NumericArrayRef ) ;
variables:
 Counter( 0 ),
 FirstCall( true ) ;
arrays:
 FibNumbers[5]( 0 ),
 FibSwingRange[5]( 0 ) ;
if FirstCall then
 begin
 FibNumbers[1] = 0.382 ;
 FibNumbers[2] = 0.5 ;
 FibNumbers[3] = 0.618 ;
 FibNumbers[4] = 0.707 ;
 FibNumbers[5] = 1 ;
 FirstCall = false ;
 end ;
for Counter = 1 to 5
 begin
 FibSwingRange[Counter] = PivotValues[ Counter + 1,
  2 ] - PivotValues[ Counter, 2] ; { $f$9 through
  $f$13 }
 end ;
for Counter = 1 to 5
 begin
 FibDateTime[Counter] = FibNumbers[Counter] *
  FibSwingRange[5] + PivotValues[6, 2] ;
 end ;
for Counter = 6 to 10
 begin
 FibDateTime[Counter] = FibNumbers[ Counter - 5 ] *
  FibSwingRange[4] + PivotValues[6, 2] ;
 end ;
for Counter = 11 to 15
 begin
 FibDateTime[Counter] = FibNumbers[ Counter - 10 ] *
  FibSwingRange[2] + PivotValues[6, 2] ;
 end ;
for Counter = 16 to 20
 begin
 FibDateTime[Counter] = ( PivotValues[5, 2] -
  PivotValues[3, 2] ) * FibNumbers[ Counter - 15 ] +
    PivotValues[5, 2] ;
 end ;
for Counter = 21 to 25
 begin
 FibDateTime[Counter] = ( PivotValues[5, 2] -
  PivotValues[1, 2] ) * FibNumbers[ Counter - 20 ] +
  PivotValues[5, 2] ;
 end ;
 
FibTimeForecasts = 1 ;
Indicator: SqOf9_FibTimeComment
{
Square of Nine portions taken from:
https://www.tradestationworld.com/discussions/Topic.aspx?
TOPIC_ID=8289


Fibonacci time forecasts come directly from the TASC 1992 Robert Miner article, "A Spreadsheet for Time Ratio Analysis."

The commentary features were written by Mitch Shack of TradeStation Securities, Inc.

Any misinterpretations of Fibonacci and Gann are my own.
--Mark Mills, TradeStation Securities, Inc.

}
inputs:
 YestDate( ELDate( 8, 10, 2004 ) ),
 TextPlaceTime( 1200 ),
 TextColor( White ),
 LineColor( Yellow ),
 LineStyle_1to5(1),
 ForecastWidth_0to6( 4 ),
 PriceForecastRange( 3 ),
 BaseNumber( 10 ),
 Price( Close ),
 RetracePct( 5 ),
 ZigZagLineWidth( 1 ),
  TextMinMoveOffset( -5 ) ;
variables:
 xloop( 0 ),
 Counter( 0 ),
 ColumnEnd( 0 ),
 HighRange( 0 ),
 LowRange( 0 ),
 Degree( "" ),
 ID( -1 ),
 DaysAhead( 0 ),
 HoursAhead( 0 ),
 MinutesAhead( 0 ),
 oFutureDate( 0 ),
 oFutureTime( 0 ),
 ValueSpace( 8 ),
 ValueSpace2( 11 ), { Print spacing }
 ValueSpace3( 4 ),
 ValueSpace4( 13 ),
 ValueSpace5( 14 ),
 YesClose( 0 ),
 ZeroDegrees( 1 ),
 FortyFiveDegrees( 2 ),
 NinetyDegrees( 3 ),
 OneThirtyFiveDegrees( 4 ),
 OneEightyDegrees( 5 ),
 TwoTwentyFiveDegrees( 6 ),
 TwoSeventyDegrees( 7 ),
 ThreeFifteenDegrees( 8 ),
 { Array Index Positions }
 DegreeSections( 8 ),
 FullArrayCount( 49 ),
 MyBaseNumber( 0 ),
 NewSwingPrice( 0 ),
 SwingPrice( Price ), { used as a convenient
  2-element array }
 SwingDate( Date ), { used as a convenient
  2-element array }
 SwingTime( Time ), { used as a convenient
  2-element array }
 TLDir( 0 ), { TLDir = -1 implies prev TL dn, +1
  implies prev TL up }
 RetraceFctrUp( 1 + RetracePct * 0.01 ),
 RetraceFctrDn( 1 - RetracePct * 0.01 ),
 SaveSwing( false ),
 AddTL( false ),
 UpdateTL( false ),
 TLRef( 0 ) ;
arrays:
 ZigZagPivots[6, 2]( 0 ), { ZigZagPivots[Row1-6, 1] =
  price, ZigZagPivots[Row1-6, 2] = date }
  FibTimeTargets[25]( 0 ),
 DegreeOfAngle[8, 49]( 0 ),
 DegreeOfAngleWord[8]( "" ) ;
if CurrentBar = 1 then
 begin
 MyBaseNumber = BaseNumber * 7 ;
 DegreeOfAngle[ ZeroDegrees, 0 ] = BaseNumber * 2 ;
 DegreeOfAngle[ FortyFiveDegrees, 0 ] =
  BaseNumber * 3 ;
 DegreeOfAngle[ NinetyDegrees, 0 ] = BaseNumber * 4 ;
 DegreeOfAngle[ OneThirtyFiveDegrees, 0 ] =
  BaseNumber * 5 ;
 DegreeOfAngle[ OneEightyDegrees, 0 ] =
  BaseNumber * 6 ;
 DegreeOfAngle[ TwoTwentyFiveDegrees, 0 ] =
  BaseNumber * 7 ;
 DegreeOfAngle[ TwoSeventyDegrees, 0 ] =
  BaseNumber * 8 ;
 DegreeOfAngle[ ThreeFifteenDegrees, 0 ] =
  BaseNumber * 9 ;
 Degree = " deg" ; { the degree symbol number }
 DegreeOfAngleWord[ ZeroDegrees ] = " - 0" + Degree ;
 DegreeOfAngleWord[ FortyFiveDegrees ] = " - 45" +
  Degree ;
 DegreeOfAngleWord[ NinetyDegrees ] = " - 90" +
  Degree ;
 DegreeOfAngleWord[ OneThirtyFiveDegrees ] = " - 135"
  + Degree ;
 DegreeOfAngleWord[ OneEightyDegrees ] = " - 180" +
  Degree ;
 DegreeOfAngleWord[ TwoTwentyFiveDegrees ] = " - 225"
  + Degree ;
 DegreeOfAngleWord[ TwoSeventyDegrees ] = " - 270" +
  Degree ;
 DegreeOfAngleWord[ ThreeFifteenDegrees ] = " - 315"
  + Degree ;
 for xLoop = 1 to FullArrayCount
  begin
  DegreeOfAngle[ ZeroDegrees, xLoop ] =
   DegreeOfAngle[ ZeroDegrees, xloop - 1 ]
   + DegreeOfAngle[ ZeroDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
 
   DegreeOfAngle[ FortyFiveDegrees, xLoop ] =
   DegreeOfAngle[ FortyFiveDegrees, xloop - 1 ]
   + DegreeOfAngle[ FortyFiveDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
 
  DegreeOfAngle[ NinetyDegrees, xLoop ] =
   DegreeOfAngle[ NinetyDegrees, xloop - 1 ]
   + DegreeOfAngle[ NinetyDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
 
  DegreeOfAngle[ OneThirtyFiveDegrees, xLoop ] =
   DegreeOfAngle[ OneThirtyFiveDegrees,
    xloop - 1 ]
   + DegreeOfAngle[ OneThirtyFiveDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
 
  DegreeOfAngle[ OneEightyDegrees, xLoop ] =
   DegreeOfAngle[ OneEightyDegrees, xloop - 1 ]
   + DegreeOfAngle[ OneEightyDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
 
  DegreeOfAngle[ TwoTwentyFiveDegrees, xLoop ] =
   DegreeOfAngle[ TwoTwentyFiveDegrees,
    xloop - 1 ]
   + DegreeOfAngle[ TwoTwentyFiveDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
  DegreeOfAngle[ TwoSeventyDegrees, xLoop ] =
   DegreeOfAngle[ TwoSeventyDegrees, xloop - 1 ]
   + DegreeOfAngle[ TwoSeventyDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
   DegreeOfAngle[ ThreeFifteenDegrees, xLoop ] =
   DegreeOfAngle[ ThreeFifteenDegrees, xloop - 1 ]
   + DegreeOfAngle[ ThreeFifteenDegrees, 0 ]
   + MyBaseNumber + ( 8 * ( xLoop - 1 ) ) ;
  end ;
 end ; { CurrentBar = 1 }
if Date <> Date[1] then
 YesClose = Close[1] ; { if new day get the SO9
  compare number }
 
{ ZigZag Calculations }
{ Candidate swings are just-confirmed, 3-bar (Str = 1),
SwingHi's and SwingLo's }
NewSwingPrice = SwingHigh( 1, Price, 1, 2 ) ;
if NewSwingPrice  <> -1 then
 begin
 if TLDir <= 0 and NewSwingPrice >= SwingPrice *
  RetraceFctrUp then { prepare to add new up TL }
  begin
  SaveSwing = true ;
  AddTL = true ;
  TLDir = 1 ;
  end
 else if TLDir = 1 and NewSwingPrice >= SwingPrice
  then { prepare to update prev up TL }
  begin
  SaveSwing = true ;
  UpdateTL = true ;
  end ;
 end
else
 begin
 NewSwingPrice = SwingLow( 1, Price, 1, 2 ) ;
 if NewSwingPrice <> -1 then
  begin
  if TLDir >= 0 and NewSwingPrice <= SwingPrice *
   RetraceFctrDn then
   { prepare to add new dn TL }
   begin
   SaveSwing = true ;
   AddTL = true ;
   TLDir = -1 ;
   end
  else if TLDir = -1 and NewSwingPrice <= SwingPrice
   then { prepare to update prev dn TL }
   begin
   SaveSwing = true ;
   UpdateTL = true ;
   end ;
  end ;
 end ;
if SaveSwing then
 { save new swing and reset SaveSwing }
 begin
 SwingPrice = NewSwingPrice ;
 SwingDate = Date[1] ;
 SwingTime = Time[1] ;
 SaveSwing = false ;
 end ;
if AddTL then { add new TL and reset AddTL }
 begin
 Plot1( Close ) ; { marks the point at which a leg of
  pivot is locked down }
 { push the pivot date and time into the array }
 { ZigZagPivots[Row1 - 6, 1] = price,
  ZigZagPivots[Row1 - 6, 2] = date, row 1 is the
  oldest }
 for Value1 = 1 to 5
  begin
  ZigZagPivots[ Value1, 2 ] = ZigZagPivots[ Value1 +
    1, 2 ] ;
  end ;
 ZigZagPivots[6,2] = DateToJulian( SwingDate ) +
  TimeToMinutes( SwingTime ) / ( 24 * 60 ) ;
 for Value1 = 1 to 5
  begin
  ZigZagPivots[ Value1, 1] = ZigZagPivots[ Value1 +
    1, 1 ] ;
  end ;
 ZigZagPivots[6,1] = SwingPrice ;
 Value1 = FibTimeForecasts( ZigZagPivots,
  FibTimeTargets ) ;
 { back to the original ZigZag code }
 TLRef = TL_New( SwingDate, SwingTime, SwingPrice,
  SwingDate[1], SwingTime[1], SwingPrice[1] ) ;
 TL_SetExtLeft( TLRef, false ) ;
 TL_SetExtRight( TLRef, false ) ;
 TL_SetSize( TLRef, ZigZagLineWidth ) ;
 TL_SetColor( TLRef, LineColor ) ;
 AddTL = false ;
 end
else if UpdateTL then
 { update prev TL and reset UpdateTL }
 begin
 TL_SetEnd( TLRef, SwingDate, SwingTime,
  SwingPrice ) ;
 UpdateTL = false ;
 end ;
if AtCommentaryBar then
 begin
 xLoop = 0 ;
 ColumnEnd = 0 ;
 while xLoop < FullArrayCount and ColumnEnd = 0
  begin
  xLoop = xLoop + 1 ;
  if DegreeOfAngle[ ZeroDegrees, xLoop ] > YesClose
   then
   ColumnEnd = xLoop ; { searching for SO9 numbers
    that are between YesClose }
  end ;
 LowRange = IntPortion( YesClose -
  PriceForecastRange ) ;
 HighRange = IntPortion( YesClose +
  PriceForecastRange ) ;
 for Counter = ColumnEnd - 1 to ColumnEnd
  begin
  for xLoop = 1 to DegreeSections
   begin
   if IFFLogic( DegreeOfAngle[ xLoop, Counter ] >=
    LowRange and DegreeOfAngle[ xLoop, Counter] <=
    HighRange, true, false ) then
    begin
    for Value99 = 1 to 25
     begin
     MinutesAhead = ( IntPortion(
      FibTimeTargets[Value99] - ( DateToJulian
      ( date ) + ( TimeToMinutes( Time ) / (
      60 * 24 ) ) ) ) ) * ( 60 * 24 ) ;
     Value1 = TimeForecast( Date, Time, 0, 0,
       MinutesAhead, oFutureDate,
      oFutureTime ) ;
     Value1 = TL_New( oFutureDate,
      oFutureTime, DegreeOfAngle[ xLoop,
      Counter ], oFutureDate, oFutureTime,
      DegreeOfAngle[ xLoop, Counter ] -
      MinMove / PriceScale ) ;
     TL_SetStyle(Value1,LineStyle_1to5);
     TL_SetSize( Value1, ForecastWidth_0to6 ) ;
     ID = Text_New( Date, TextPlaceTime,
      DegreeOfAngle[ xLoop, Counter ] +
      TextMinMoveOffset * MinMove /
      PriceScale, NumToStr( DegreeOfAngle[
      xLoop, Counter ], 0 ) +
      DegreeOfAngleWord[xLoop] ) ;
     Value1 = Text_SetColor( ID, TextColor ) ;
     end ; { FibTimeTargets loop }
    end ; { IFFLogic }
   end ; { xLoop }
  end ; { Counter }
 end ; { Date = }
--Mark Mills
MarkM@TSSec at www.TradeStationWorld.com
EasyLanguage Questions Forum
TradeStation Securities, Inc.
A subsidiary of TradeStation Group, Inc.


GO BACK


AMIBROKER: Fibonacci And Gann Projections

In "Fibonacci And Gann Projections," Dennis Peterson shows how to display time projections based on the zigzag indicator and Fibonacci ratios, as well as price projections based on Gann square of nine calculations. This kind of analysis can be relatively easily reproduced using AmiBroker's own programming language, AFL.

The code in Listing 1 plots the zigzag indicator overlaid on a price chart plus projected time/price points (blue/orange dots). Using AmiBroker, one does not need the bar replay feature used in the eSignal code referred to in the article [and printed in this Traders' Tips section --Ed.], because the same effect could be achieved by AFL coding alone. The code presented here uses AmiBroker's vertical selector line to allow the user to choose the ending point. All "future" bars (after the selection line) are plotted in a gray color, while "past" bars are plotted in black (Figure 2). Projections are plotted according to user date selection, with blue dots (time projections) and orange dots (square of nine price projections). As an alternative, the user may download a free program from AmiBroker's mailing list (https://finance.groups.yahoo.com/group/amibroker/files/Simulator124.zip) that provides the bar replay feature to all AmiBroker users.

Figure 2: AMIBROKER, Fibonacci And Gann Projections. This screenshot shows a daily chart of Microsoft (MSFT) with an overlaid zigzag line as well as time and price projection points (blue/orange dots). Note that a significant market bottom has been successfully predicted by the three dots clustered between November 14 and 26.
LISTING 1
Change = 5;
GannIncrement = 0.0625;
procedure PlotShapeAt( x, y, shape, shift )
{
  PlotShapes( IIf( BarIndex() == x, shape, 0 ), colorRed, 0, y, shift );
}
procedure PlotBlueDot( x, y )
{
  PlotShapes( IIf( BarIndex() == x, shapeSmallCircle, 0 ),
              colorBlue, 0, y, 0  );
 
  for( i = -2; i <= 2; i++ )
  {
   if( i != 0 )
   {
      yGann = ( sqrt( y ) + i * GannIncrement ) ^ 2;
      PlotShapes( IIf( BarIndex() == x, shapeSmallCircle, 0 ),
                  colorOrange, 0, yGann, 0  );
   }
  }
}
bi = BarIndex();
sbi = SelectedValue( bi );
GraphXSpace = 2;
Plot( Zig( C, Change ), "Zigzag", colorGreen, styleThick );
Plot( C, "Price", IIf( bi > sbi, colorLightGrey, colorBlack ), styleBar );
upshift = 15;
if( SelectedValue( PeakBars( C, Change ) < TroughBars( C, Change ) ) )
{
   pt1 = PeakBars( C, Change, 1 ) == 0 ;
   pt2 = TroughBars( C, Change, 1 ) == 0 ;
}
else
{
   pt1 = TroughBars( C, Change, 1 ) == 0 ;
   pt2 = PeakBars( C, Change, 1 ) == 0 ;
   upshift = -upshift;
}
bpt1 = SelectedValue( ValueWhen( pt1, bi ) );
bpt2 = SelectedValue( ValueWhen( pt2, bi ) );
bpt3 = SelectedValue( ValueWhen( pt1, bi, 2 ) );
bpt4 = SelectedValue( ValueWhen( pt2, bi, 2 ) );
bpt5 = SelectedValue( ValueWhen( pt1, bi, 3 ) );
bpt6 = SelectedValue( ValueWhen( pt2, bi, 3 ) );
PlotShapeAt( bpt1, C, shapeDigit1, upshift );
PlotShapeAt( bpt2, C, shapeDigit2, -upshift  );
PlotShapeAt( bpt3, C, shapeDigit3, upshift );
PlotShapeAt( bpt4, C, shapeDigit4, -upshift );
PlotShapeAt( bpt5, C, shapeDigit5, upshift );
PlotShapeAt( bpt6, C, shapeDigit6, -upshift );
Level = SelectedValue( ValueWhen( pt1, C ) );
PlotBlueDot( round( bpt1 + 1.618 * ( bpt1 - bpt2 ) ), Level );
PlotBlueDot( round( bpt1 + 0.382 * ( bpt1 - bpt2 ) ), Level );
PlotBlueDot( round( bpt1 + 0.5 * ( bpt2 - bpt3 ) ), Level );
PlotBlueDot( round( bpt1 + 1.732 * ( bpt2 - bpt3 ) ), Level );
PlotBlueDot( round( bpt1 + 0.618 * ( bpt4 - bpt5 ) ), Level );
PlotBlueDot( round( bpt1 + 2 * ( bpt4 - bpt5 ) ), Level );
PlotBlueDot( round( bpt2 + 0.6707 * ( bpt4 - bpt2 ) ), Level );
PlotBlueDot( round( bpt2 + 2.618 * ( bpt4 - bpt2 ) ), Level );
PlotBlueDot( round( bpt2 + 1 * ( bpt6 - bpt2 ) ), Level );
PlotBlueDot( round( bpt2 + 3 * ( bpt6 - bpt2 ) ), Level );


--Tomasz Janeczko, AmiBroker.com
www.amibroker.com

GO BACK


WEALTH-LAB: Fibonacci And Gann Projections

When we were provided with an advance copy of Dennis Peterson's article for this issue, "Fibonacci And Gann Projections," with its 500+ lines of eSignal code and comments, we knew this Traders' Tip was going to present a good programming challenge (it did). Making use of our trusty ZigZagX study from the November 2003 Traders' Tips, we squeezed the implementation into 150 sparsely commented lines of WealthScript code. The study's swing line colors were changed, however, to be compatible with our chart's color scheme (Figure 3).

Figure 3: WEALTH-LAB. Fibonacci And Gann Projections. With the DrawImage function in Wealth-Lab, you can plot any bitmap image in any location on the chart, as we did here. The blue and yellow dots are the projections from the last confirmed swing, whereas the green and red diamonds are relative to unconfirmed swings in formation. We added the Fibonacci Time Zones using the drawing toolbar (far right).


The script automatically adds space to the right of the final bar, and off-the-chart Fibonacci projections show up on a light red background on the far right. Finally, programmers may be interested in the use of the variant array and especially in the recursive routine used to fill another array containing the bar numbers of swing points.
 

WealthScript code:
{$I 'ZigZagX Study'}
const revPct = 5.0; // Reversal percentage
const MaxFutureBars = 100;
const GannIncr = 0.25;
const GannPjs = 2; // 4 gann projs above, below
const Np = 9;      // 10 fib projections
const SwPts = 8;   // 7 swings, 1 unconf'd, 1 extra
{ array of swing bar numbers }
var swgBar: array[0..SwPts] of integer;
{ fib projections in time, contains Bar Numbers }
var fp: array[0..Np] of integer;
{ swing distances (bars) corresponding to fp }
var sd: array[0..Np] of integer;
{ gann price projections, Confirmed & Unconfirmed }
var gp: array[-1 * GannPjs..GannPjs] of float;
var Bar, Series: integer;
var fib: COMVariantArray;
var Rtr, Chg: float;
       { DR1, DR2, A11, A12, A21, A22, C1, C2, D1, D2 }
fib := [0.382,1.618,0.5,1.732,0.618,2,0.707,2.618,1,3];
Series := #Close;
procedure MakeSpace( Number: integer );
begin
  AddFutureBars( Number );
  for Bar := BarCount - 1 downto 0 do
    if SyntheticBar( Bar ) then
      SetBarColor( Bar, #Black )
    else break;
end;
procedure DrawProjections( Conf: integer );
begin
  var i, j: integer;
  var Img1: string = 'RedDiamond';
  var Img2: string = 'GreenDiamond';
  if Conf = 1 then
  begin
    Img1 := 'YellowDot';
    Img2 := 'BlueDot';
  end;
  for i := 0 to SwPts do
    for j := -GannPjs to GannPjs do
      if j > 0 then
        DrawImage( Img1, 0, fp[i], gp[j], false )
      else if j < 0 then
        DrawImage( Img1, 0, fp[i], gp[j], true )
      else
        DrawImage( Img2, 0, fp[i], gp[j], true );
end;
{ Pass Conf = 1 for confirmed swing }
procedure ProjectFibs( Conf: integer );
begin
{ swg is the period between swings}
  var swgPer: array[0..Np] of integer;
  var j: integer;
  swgPer[0] := swgBar[Conf] - swgBar[Conf+1];
  swgPer[1] := swgPer[0];
  swgPer[2] := swgBar[Conf+1] - swgBar[Conf+2];
  swgPer[3] := swgPer[2];
  swgPer[4] := swgBar[Conf+3] - swgBar[Conf+4];
  swgPer[5] := swgPer[4];
  swgPer[6] := swgBar[Conf+1] - swgBar[Conf+3];
  swgPer[7] := swgPer[6];
  swgPer[8] := swgBar[Conf+1] - swgBar[Conf+5];
  swgPer[9] := swgPer[8];
  if Conf = 1 then
    for j := 0 to Np do
      if j < 6 then
        fp[j] := swgBar[1] + Round( swgPer[j] * fib[j] )
      else
        fp[j] := swgBar[2] + Round( swgPer[j] * fib[j] );
  if Conf = 0 then
    for j := 0 to Np do
      if j < 6 then
        fp[j] := swgBar[0] + Round( swgPer[j] * fib[j] )
      else
        fp[j] := swgBar[1] + Round( swgPer[j] * fib[j] );
  DrawProjections( Conf );
end;
{ Fills array with Gann projections }
procedure SqrOf9( Conf: integer );
begin
  var g: integer;
  var Prc: float = GetSeriesValue( swgBar[Conf], Series );
  for g := -GannPjs to GannPjs do
    if g = 0 then
      gp[0] := Prc
    else
      gp[g] := Sqr( Sqrt( Prc ) + g * GannIncr );
  ProjectFibs( Conf );
end;
{ Uses recursion to fill array w/ swing bar numbers }
procedure FillSwingBars( Idx, pb, tb: integer );
begin
  var pBar, tBar: integer;
  var uSwg, f: float;
  pBar := PeakBar( pb, Series, revPct );
  tBar := TroughBar( tb, Series, revPct );
  if pBar > tBar then  // peak is last
  begin
    if Idx = 0 then
    begin
      swgBar[0] := LowestBar( pb, Series, pb - pBar );
      f := GetSeriesValue( swgBar[0], Series );
      uSwg := PriceClose( pBar ) - f;
      Rtr := uSwg/(PriceClose( pBar ) - PriceClose( tBar ));
      Chg := ( PriceClose( pb ) - f ) / uSwg;
      Inc( Idx );
    end;
    swgBar[Idx] := pBar;
    Inc( Idx );
    swgBar[Idx] := tBar;
  end else             // trough is last
  begin
    if Idx = 0 then
    begin
      swgBar[0] := HighestBar( tb, Series, tb - tBar );
      f := GetSeriesValue( swgBar[0], Series );
      uSwg := f - PriceClose( tBar );
      Rtr := uSwg/(PriceClose( pBar ) - PriceClose( tBar ));
      Chg := ( f - PriceClose( tb ) ) / uSwg;
      Inc( Idx );
    end;
    swgBar[Idx] := tBar;
    Inc( Idx );
    swgBar[Idx] := pBar;
  end;
  Inc( Idx );
  if Idx < SwPts then
    FillSwingBars( Idx, pBar - 1, tBar - 1 );
end;
HideVolume;
SetColorScheme( #Lime,922,#Olive,#Black,#Silver,#Silver );
ZigZagX( #Close, 0, revPct, false );
FillSwingBars( 0, BarCount - 1, BarCount - 1);
SqrOf9( 1 );  SqrOf9( 0 );
MakeSpace( 75 );
SetBackgroundColor( BarCount - 1, #RedBkg );
SetBarColor( BarCount - 1, #RedBkg );
DrawLabel('Retrace: '+ FormatFloat( '0.0%', 100*Rtr ), 0 );
DrawLabel('Change: '+ FormatFloat( '0.0%', 100*Chg ), 0 );


--Robert Sucher
www.wealth-lab.com


GO BACK


eSIGNAL: Fibonacci And Gann Projections

Here is the eSignal code for the Fibonacci and Gann projections technique given in Dennis Peterson's article in this issue, "Fibonacci And Gann Projections."
 

/*****************************************************************
Provided By : eSignal. (c) Copyright 2004
Study:        Swing Prediction
Version:      1.0
Formula Parameters:                 Default:
    * Swing: # of Bars              1
This is the minimum number of bars required to define a swing point.
This number is for both sides of the swing point (i.e. 5 bars on
 the left and right of the swing bar).
    * Swing: Wave Type              % Change in Price
        (% Retracement, % Change in Price)
    * Swing: Wave Percentage        5
The number 5 will be treated as 5.0%.
The number 0.05 will be treated as 0.0005%.
    * Swing High Price Source       Close
    * Swing Low Price Source        Close
    * Line Thickness                2
    * Confirmed Swing Line Color    Blue
    * Developing Swing Line Color   Yellow
    * Number of Swings for Gann     1
The number of previous swings points to be included in the Gann projections
    * Gann Increment                0.25
The +/- increment for Gann calculation above and below the base calculation for Gann.
    * Number of Gann Increments     2
        The number of Gann increments to be calculated above and below
        the Gann basis calculation. 2 will draw one above and one below the basis.
    * Fibonacci: DR 1               0.382
    * Fibonacci: DR 2               1.618
    * Fibonacci: A1 1               0.5
    * Fibonacci: A1 2               1.732
    * Fibonacci: A2 1               0.618
    * Fibonacci: A2 2               2.0
    * Fibonacci: C 1                0.707
    * Fibonacci: C 2                2.618
    * Fibonacci: DC 1               1.0
    * Fibonacci: DC 2               3.0
*****************************************************************/
function preMain() {
    setPriceStudy(true);
    setStudyTitle("Swing Prediction ");
    setShowCursorLabel(false);
    setShowTitleParameters(false);
 
    var fp1 = new FunctionParameter("nNum", FunctionParameter.NUMBER);
    fp1.setName("Swing: # of Bars");
    fp1.setLowerLimit(1);
    fp1.setDefault(1);
 
    var fp2a = new FunctionParameter("sWaveType", FunctionParameter.STRING);
    fp2a.setName("Swing: Wave Type");
    fp2a.addOption("% Retracement");
    fp2a.addOption("% Change in Price");
    fp2a.setDefault("% Change in Price");
 
    var fp2 = new FunctionParameter("nRet", FunctionParameter.NUMBER);
    fp2.setName("Swing: Wave Percentage");
    fp2.setLowerLimit(0);
    fp2.setDefault(5);
    var fp3 = new FunctionParameter("sHighSource", FunctionParameter.STRING);
    fp3.setName("Swing High Price Source");
    fp3.addOption("Open");
    fp3.addOption("High");
    fp3.addOption("Low");
    fp3.addOption("Close");
    fp3.setDefault("Close");
    var fp4 = new FunctionParameter("sLowSource", FunctionParameter.STRING);
    fp4.setName("Swing Low Price Source");
    fp4.addOption("Open");
    fp4.addOption("High");
    fp4.addOption("Low");
    fp4.addOption("Close");
    fp4.setDefault("Close");
    var fp5 = new FunctionParameter("nThickness", FunctionParameter.NUMBER);
    fp5.setName("Line Thickness");
    fp5.setLowerLimit(1);
    fp5.setDefault(2);
    var fp6 = new FunctionParameter("cColor1", FunctionParameter.COLOR);
    fp6.setName("Confirmed Swing Line Color");
    fp6.setDefault(Color.blue);
    var fp7 = new FunctionParameter("cColor2", FunctionParameter.COLOR);
    fp7.setName("Developing Swing Line Color");
    fp7.setDefault(Color.yellow);
 
    var fp19 = new FunctionParameter("nGann", FunctionParameter.NUMBER);
    fp19.setName("Number of Swings for Gann");
    fp19.setLowerLimit(1);
    fp19.setUpperLimit(6);
    fp19.setDefault(1);
 
    var fp19b = new FunctionParameter("nGannInc", FunctionParameter.NUMBER);
    fp19b.setName("Gann Increment");
    fp19b.setLowerLimit(0);
    fp19b.setDefault(0.25);
    var fp19c = new FunctionParameter("nGannNum", FunctionParameter.NUMBER);
    fp19c.setName("Number of Gann Increments");
    fp19c.setLowerLimit(0);
    fp19c.setDefault(2);
    var fp20 = new FunctionParameter("fib0", FunctionParameter.NUMBER);
    fp20.setName("Fibonacci: DR 1");
    fp20.setLowerLimit(0);
    fp20.setDefault(0.382);
    var fp21 = new FunctionParameter("fib1", FunctionParameter.NUMBER);
    fp21.setName("Fibonacci: DR 2");
    fp21.setLowerLimit(0);
    fp21.setDefault(1.618);
    var fp22 = new FunctionParameter("fib2", FunctionParameter.NUMBER);
    fp22.setName("Fibonacci: A1 1");
    fp22.setLowerLimit(0);
    fp22.setDefault(0.5);
    var fp23 = new FunctionParameter("fib3", FunctionParameter.NUMBER);
    fp23.setName("Fibonacci: A1 2");
    fp23.setLowerLimit(0);
    fp23.setDefault(1.732);
    var fp24 = new FunctionParameter("fib4", FunctionParameter.NUMBER);
    fp24.setName("Fibonacci: A2 1");
    fp24.setLowerLimit(0);
    fp24.setDefault(0.618);
    var fp25 = new FunctionParameter("fib5", FunctionParameter.NUMBER);
    fp25.setName("Fibonacci: A2 2");
    fp25.setLowerLimit(0);
    fp25.setDefault(2);
    var fp26 = new FunctionParameter("fib6", FunctionParameter.NUMBER);
    fp26.setName("Fibonacci: C 1");
    fp26.setLowerLimit(0);
    fp26.setDefault(0.707);
    var fp27 = new FunctionParameter("fib7", FunctionParameter.NUMBER);
    fp27.setName("Fibonacci: C 2");
    fp27.setLowerLimit(0);
    fp27.setDefault(2.618);
    var fp28 = new FunctionParameter("fib8", FunctionParameter.NUMBER);
    fp28.setName("Fibonacci: DC 1");
    fp28.setLowerLimit(0);
    fp28.setDefault(1.0);
    var fp29 = new FunctionParameter("fib9", FunctionParameter.NUMBER);
    fp29.setName("Fibonacci: DC 2");
    fp29.setLowerLimit(0);
    fp29.setDefault(3.0);
}
var bEdit = true;       // tracks change of user inputs
var cntr = 0;           // image counter for swing lines
var bInit = false;      // initialization routine completion
var nNumBars = null;    // number of bars for defining swings
var sWaveTypeG = null;  // wave type for confirming swings
var nRetpcnt = null;    // percent retracement for defining swings
var nThicknessG = null; // line thickness
var cColorCon = null;   // confirmed swing color
var cColorDev = null;   // developing swing color
var nGannG = 1;         // number of swings for Gann calculations
var nGannIncG = null;   // increment value for Gann calculations
var nGannNumG = null;   // number of increments for Gann calculations
var sHSource = null;    // price source for high swings
var sLSource = null;    // price source for low swings
var x1a = null;         // x-coordinate for point a of developing line 1
var x1b = null;         // x-coordinate for point b of developing line 1
var x2a = null;         // x-coordinate for point a of developing line 2
var x2b = null;         // x-coordinate for point b of developing line 2
var y1a = null;         // y-coordinate for point a of developing line 1
var y1b = null;         // y-coordinate for point b of developing line 1
var y2a = null;         // y-coordinate for point a of developing line 2
var y2b = null;         // y-coordinate for point b of developing line 2
var aY2A = new Array(7);// array of current 7 swing prices
var vLastSwing = null;  // tracking swing type of last confirmed swing
var nScntr = 0;         // bar counter for swing confirmation
var aSwingsIndex = new Array(7); // tracks current swings for DR, C, DC, A1, A2 periods
var aSwingsPrice = new Array(7); // tracks current swing prices for Gann projections
var aFibs = new Array(10);       // Fibonacci numbers for Swing Predictions
var bProjCon = false;
var bProjDev = false;
var tCntr = 0;
function main(nNum, sWaveType, nRet, sHighSource, sLowSource, nThickness, cColor1, cColor2,
              nGann, nGannInc, nGannNum, fib0, fib1, fib2, fib3, fib4, fib5, fib6, fib7, fib8, fib9) {
    var nState = getBarState();
    var nIndex = getCurrentBarIndex();
    var h = getValue(sHighSource);
    var l = getValue(sLowSource);
    var c = close();
    var i = 0;
    // record keeping
    if (nState == BARSTATE_NEWBAR) {
        if (cntr > 100) cntr = 0;
        if (x1a != null) x1a -= 1;
        if (x1b != null) x1b -= 1;
        if (x2a != null) x2a -= 1;
        if (x2b != null) x2b -= 1;
        i = 0;
        for (i = 0; i < 7; ++i) {
            if (aSwingsIndex[i] != null) aSwingsIndex[i] -= 1;
        }
    }
    //Initialization
    if (bEdit == true) {
        if (nNumBars == null) nNumBars = nNum;
        if (sWaveTypeG == null) sWaveTypeG = sWaveType;
        if (nRetpcnt == null) nRetpcnt = nRet/100;
        if (nThicknessG == null) nThicknessG = nThickness;
        if (cColorCon == null) cColorCon = cColor1;
        if (cColorDev == null) cColorDev = cColor2;
        if (nGann != null) nGannG = nGann;
        if (nGannIncG == null) nGannIncG = nGannInc;
        if (nGannNumG == null) nGannNumG = Math.round(nGannNum);
        if (sHSource == null) sHSource = sHighSource;
        if (sLSource == null) sLSource = sLowSource;
        if (x1a == null) x1a = 0;
        if (y1a == null) y1a = c;
        i = 0;
        for (i = 0; i < 10; ++i) {
            aFibs[i] = eval("fib"+i);
        }
        bEdit = false;
    }
    if (bInit == false) {
        bInit = Init(h,l,c);
    }
    // Swings
    if (nState == BARSTATE_NEWBAR) {
        nScntr += 1;
        // confirmed Swings
        if (nScntr > nNumBars) {
            confirmSwings();
            if (bInit == true) {
                doLine("dev1");
                doLine("dev2");
            }
        }
    }
    checkSwings(h, l);
    if (bProjCon == true) {
        bProjCon = false;
        doProjections("con");
    }
    if (bProjDev == true) {
        bProjDev = false;
        doProjections("dev1");
    }
    if (nIndex >= -1) {
        var nWaveRet = (Math.abs(aSwingsPrice[0]-aSwingsPrice[1]) / Math.abs(aSwingsPrice[1]-aSwingsPrice[2]))*100;
        var sWaveRetText = " \%Rtmt: " + nWaveRet.toFixed(2) + " ";
        var nWaveChg = (Math.abs(y2a-y2b) / y1b)*100;
        var sWaveChgText = " \%Chg: " +  nWaveChg.toFixed(2) + " ";
        drawTextRelative(2, 25, sWaveRetText, Color.navy, Color.lightgrey,
            Text.BOLD|Text.LEFT|Text.VCENTER|Text.FRAME|Text.RELATIVETOBOTTOM,
            null, 12, "Ret");
        drawTextRelative(2, 5, sWaveChgText, Color.navy, Color.lightgrey,
            Text.BOLD|Text.LEFT|Text.VCENTER|Text.FRAME|Text.RELATIVETOBOTTOM,
            null, 12, "Chg");
    }
    return;
}
/***********************/
/******  Functions *****/
/***********************/
function Init(h,l,c) {
    if (close(-(nNumBars*2)) == null) {
        return false;
    } else {
        // Find initial line.
        // The initial line will be the first high or low swing,
        // which has the greater difference of the swing point to
        // the close of the first bar.
        var Index = getCurrentBarIndex()
        var hIndex = Index;
        var lIndex = Index;
        var j = nNumBars*2;
        var aHigh = getValue(sHSource, 0, -j);
        var aLow = getValue(sLSource, 0, -j);
        var vHH = aHigh[0];
        var vLL = aLow[0];
        var tempIndex = Index;
        var i = 0;
        for (i = 0; i < j; ++i) {
            if (aHigh[i] > vHH) {
                vHH = aHigh[i];
                hIndex = tempIndex;
            }
            if (aLow[i] < vLL) {
                vLL = aLow[i];
                lIndex = tempIndex;
            }
            tempIndex -= 1;
        }
        if (vHH - y1a > y1a - vLL) {
            vLastSwing = "L";
            x1b = hIndex - Index;
            y1b = vHH;
            doLine("dev1");
            x2a = x1b;
            y2a = vHH;
            x2b = 0;
            y2b = c;
            doLine("dev2");
        } else {
            vLastSwing = "H";
            x1b = lIndex - Index;
            y1b = vLL;
            doLine("dev1");
            x2a = x1b;
            y2a = vLL;
            x2b = 0;
            y2b = c;
            doLine("dev2");
        }
    }
 
    if (vLastSwing != null) {
        return true;
    } else {
        return false;
    }
}
function doLine(sType) {
    //confirmed
    if (sType == "con") {
        cntr += 1;
        drawLineRelative(x1a, y1a, x1b, y1b, PS_SOLID,
            nThicknessG, cColorCon, sType+cntr);
        x1a = x2a;
        y1a = y2a;
        x1b = x2b;
        y1b = y2b;
        x2a = x1b;
        y2a = y1b;
        aSwingsIndex.pop();
        aSwingsIndex.unshift(x1b);
        aSwingsPrice.pop();
        aSwingsPrice.unshift(y1b);
        if (vLastSwing == "H") y2b = getValue(sHSource);
        if (vLastSwing == "L") y2b = getValue(sLSource);
        aY2A.pop();
        aY2A.unshift(y2a);
        if (aSwingsIndex[6] != null) {
            bProjCon = true;
        }
    }
    // dev1
    if (sType == "dev1") {
        drawLineRelative(x1a, y1a, x1b, y1b, PS_SOLID,
            nThicknessG, cColorDev, sType);
        aSwingsIndex[0] = x1b;
        aSwingsPrice[0] = y1b;
        if (aSwingsIndex[6] != null && getCurrentBarIndex() >= -1) {
            bProjDev = true;
        }
    }
 
    // dev2
 
    if (sType == "dev2") {
        if (x2a != 0 && x2a != x2b) {
            if ( (vLastSwing == "H" && sHSource == "Close") || (vLastSwing == "L" && sLSource == "Close") ) {
                x2b = 0;
                y2b = close();
            }
            drawLineRelative(x2a, y2a, x2b, y2b, PS_SOLID,
                nThicknessG, cColorDev, sType);
        } else {
            removeLine(sType);
        }
    }
    return;
}
function confirmSwings() {
    if (x1b != x2b) {   // underdeveloped dev1 line
        if (sWaveTypeG == "% Retracement") {
            var nWave = (Math.abs(y2a-y2b) / Math.abs(y1b-y1a));
        } else {
            var nWave = (Math.abs(y2a-y2b) / y1b);
        }
        if (vLastSwing == "L" && nWave >= nRetpcnt ) {
            // Swing High
            nScntr = 0;
            vLastSwing = "H";
            doLine("con");
        } else if (vLastSwing == "H" && nWave >= nRetpcnt ) {
            // Swing Low
            nScntr = 0;
            vLastSwing = "L";
            doLine("con");
        }
    }
 
    return;
}
function checkSwings(h, l) {
    // dev1
    if (vLastSwing == "L") {         // find Swing High
        if (h >= y1b) {  // higher high, no swing
            nScntr = 0;
            x1b = 0;
            y1b = h;
            doLine("dev1");
            x2a = 0;
            y2a = h;
        }
    } else if (vLastSwing == "H") {  // find Swing Low
        if (l <= y1b) {  // Lower low, no swing
            nScntr = 0;
            x1b = 0;
            y1b = l;
            doLine("dev1");
            x2a = 0;
            y2a = l;
        }
    }
    // dev2
    if (nScntr == 0) {
        x2b = 0;
        if (vLastSwing == "H") y2b = h;
        if (vLastSwing == "L") y2b = l;
    } else {
        if (vLastSwing == "H" && h >= y2b) {
            y2b = h; x2b = 0;
        } else if (vLastSwing == "L" && l <= y2b) {
            y2b = l; x2b = 0;
        }
    }
    doLine("dev2");
    return;
}
function doProjections(sName) {
    var i = 0;
    var j = 0;
    var k = 0;
    var nGannTot = (nGannNumG*2) + 1; // total number of Gann rows
    var aX = new Array(10);
    var aY = new Array(10);
    var aSwingPeriods = new Array(10);
    var nOffset = 0;  // 0 for developing swings, 1 for confirmed swings
 
    if (sName == "con") nOffset = 1;
    var DR = aSwingsIndex[0+nOffset] - aSwingsIndex[1+nOffset];
    aSwingPeriods[0] = DR;
    aSwingPeriods[1] = DR;
    var C  = aSwingsIndex[1+nOffset] - aSwingsIndex[3+nOffset];
    aSwingPeriods[2] = C;
    aSwingPeriods[3] = C;
    var DC = aSwingsIndex[1+nOffset] - aSwingsIndex[5+nOffset];
    aSwingPeriods[4] = DC;
    aSwingPeriods[5] = DC;
    var A1 = aSwingsIndex[1+nOffset] - aSwingsIndex[2+nOffset];
    aSwingPeriods[6] = A1;
    aSwingPeriods[7] = A1;
    var A2 = aSwingsIndex[3+nOffset] - aSwingsIndex[4+nOffset];
    aSwingPeriods[8] = A2;
    aSwingPeriods[9] = A2;
 
    if (sName == "con") {
        i = 0;
        for (i = 0; i < nGannG; ++i) {
            for (k = 0; k < 10; ++k) {
                for (j = 0; j < nGannTot; ++j) {
                    removeShape("dev1Proj"+i+k+j);
                }
            }
        }
    }
 
    // X - Projections
    // anchor is from end of DR wave for DR, A1 and A2
    // anchor is from beginning of DR wave for C and DC
    i = 0;
    for (i = 0; i < 10; ++i) {
        if (i >= 2 && i <= 5) { // C and DC
            aX[i] = Math.round((aSwingPeriods[i] * aFibs[i]) + aSwingsIndex[1+nOffset]);
        } else { // DR, A1 and A2
            aX[i] = Math.round((aSwingPeriods[i] * aFibs[i]) + aSwingsIndex[0+nOffset]);
        }
    }
 
    // Y - Projections
    var aY = new Array(nGannG); // number of swings
    i = 0;
    for (i = 0; i < nGannG; ++i) {
        aY[i] = new Array(nGannTot);    // number of rows per swing
    }
    i = 0;
    for (i = 0; i < nGannG; ++i) {
        var nBasis = Math.sqrt(aSwingsPrice[i+nOffset]);
        var nNum = (nGannIncG * nGannNumG);
        for (j = 0; j < nGannTot; ++j) {
            aY[i][j] = (nBasis + nNum) * (nBasis + nNum);
            nNum -= nGannIncG;
        }
    }
 
    // plot Swing Predictions
    i = 0;
    for (i = 0; i < nGannG; ++i) {  // number of swings
        for (k = 0; k < 10; ++k) {  // 10 swing periods (5 waves * 2 fibs for each)
            for (j = 0; j < nGannTot; ++j) {  // total rows per swing
                var ShapeFlags = null;
                if (sName == "con") {
                    var ProjColor = cColorDev;
                    var vShape = "Shape.CIRCLE";
                } else {
                    var ProjColor = Color.red;
                    var vShape = "Shape.DIAMOND";
                }
                if (j == ((nGannTot/2)-.5) ) {
                    if (sName == "con") {
                        ProjColor = cColorCon;
                        vShape = "Shape.CIRCLE";
                    } else {
                        ProjColor = Color.green;
                        vShape = "Shape.DIAMOND";
                    }
                    ShapeFlags = "Shape.ONTOP";
                }
                drawShapeRelative(aX[k], aY[i][j], eval(vShape), null, ProjColor,
                    eval(ShapeFlags), sName + "Proj"+i+k+j);
            }
        }
    }
 
    return;
}
--Jason Keck
eSignal, a division of Interactive Data Corp.
800 815-8256, www.esignalcentral.com


GO BACK


NEUROSHELL TRADER: Fibonacci And Gann Projections

In "Fibonacci And Gann Projections," Dennis Peterson presents eSignal code [printed in this Traders' Tips section--Ed.] designed to help predict turning points, or peaks and valleys. However, NeuroShell Trader Professional has an inexpensive add-on already available to do just that. We will use the peak and valley probability indicators from our Turning Points add-on.

After installing the Turning Points add-on, you can insert the peak and valley probability indicators by doing the following:

1. Select "New Indicator ..." from the Insert menu.
2. Select the Turning Points category.
3. Select the PeakProb, ValleyProb, and TPplot indicators.
4. Select the Neighborhood and Window Size as you desire.


The peak probability and valley probability indicators use the mean and standard deviation of the percent change in value from peak to valley or from valley to peak. Once these two characteristics of the percent change are known in the lookback window, it is possible to compute the probability that the most recent bar is at a new peak or at a new valley. The Turning Points add-on algorithm does not just blindly search for the first consecutive valley after a peak (or a first consecutive peak after a valley); it tries to optimize on turning points and locates such peaks and valleys as a human expert would choose by looking at the chart.

In addition to probabilities based on percent change, the Turning Points add-on includes indicators to provide probabilities for peaks and valleys based on horizontal change (bars), as well as many other statistical measures.

The TPplot indicator may be used as a visual aid for peak and valley locations on the chart. It connects consecutive TPs with straight lines (Figure 4).

Figure 4: NEUROSHELL TRADER, Fibonacci And Gann Projections. This NeuroShell Trader chart displays bar charts of the probabilities of peaks and valleys created with the Turning Points add-on. The data displayed is from the paper-trading (out-of-sample) period.


You can automatically backtest the usefulness of the peak and valley probability indicators by inserting them into a Trading Strategy as follows:

1.  Select "New Trading Strategy" from the Insert menu.
2.  On the Long Entry tab, select the "Add Conditions" button, Relational category, A > B.
3.  Set A = Valley Prob and B = 0.5.
4.  On the Long Exit tab, select the "Add Conditions" button, Relational category, A > B.
5.  Set A = Peak Prob, and B = 0.5.
6.  On the Short Entry tab, select the "Add Conditions" button, Relational category, A > B.
7.  Set A = Peak Prob, and B = 0.5.
8.  On the Short Exit tab, select the "Add Conditions" button, Relational category, A > B.
9.  Set A = Valley Prob and B = 0.5.
The genetic algorithm optimizer in NeuroShell Trader can find the most profitable settings, including B above as well as the neighborhood and window size. This can provide you with your own custom version of the peak and valley probability indicators that works best with your market sector.

Using NeuroShell Trader's ability to backtest and paper trade on out-of-sample data, you can get complete statistical reports on the successfulness of peak and valley trading strategies.

The example given above is but a very simple use of two of the many indicators in the Turning Points add-on. For example, you can add Fibonacci retracement levels using the Fibonacci retracement indicator. Far more complicated strategies can be built, and the indicators make great inputs to our neural networks, enabling nonlinear predictions of turning points.

Users of NeuroShell Trader who already own the Turning Points add-on can go to the STOCKS & COMMODITIES section of the NeuroShell Trader free technical support website to download a copy of the chart we built to predict future turning points.

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


GO BACK


NEOTICKER: Fibonacci And Gann Projections

To implement in NeoTicker the idea presented in "Fibonacci And Gann Projections" by Dennis Peterson, we'll use a script indicator. This indicator is named swprediction with 21 parameters. Those parameters are the same as the ones shown in the eSignal code in this section, which is referred to in the article.

To reproduce the QQQ chart (Figure 5) shown in the article using NeoTicker, first add a daily QQQ data series. Then select the data series and add swprediction with default parameters. The result will resemble the chart shown in Peterson's article.

Figure 5: NEOTICKER,  FIBONACCI AND GANN PROJECTIONS, QQQ DAILY SWING. To reproduce the QQQ chart  shown in Peterson's article, first add a daily QQQ data series. Then select the data series and add swprediction with default parameters.


Swprediction can also be added to other indexes to show projection of support and resistance levels. The SPX chart (Figure 6) has demonstrated this fact.

Figure 6:  NEOTICKER,  FIBONACCI AND GANN PROJECTIONS, SPX DAILY SWING. Swprediction can also be added to other indexes to show projection of support and resistance levels. The SPX chart demonstrates this fact.


Because the code is too long to list here, for readers who are interested in seeing this indicator in action, the indicator source code is available for download at the NeoTicker Yahoo! User Group site.

--Kenneth Yuen, TickQuest Inc.
www.tickquest.com


GO BACK


PROPHET.NET: Fibonacci And Gann Projections

Fibonacci and Gann projections, described by Dennis Peterson in his article in this issue, are available on the Prophet.Net website to all premium members. No coding is required on the part of the user. The indicator is built into the JavaCharts applet.

We have created two indicators in JavaCharts based on Peterson's article: Fibonacci-Gann Projections Change %, and Fibonacci-Gann Projections Retrace %, which are useful for detecting swings. For one-click access to these indicators, go to JavaCharts from your computer's browser:
 

 https://www.prophet.net/analyze/javacharts.jsp


or click the "Analyze" tab on the Prophet.net website, then click the JavaCharts selection:

Click on the Tools menu (which you can also access by right-clicking anywhere on a chart) and choose "Apply Studies" from the Studies menu item. The list of available studies (approximately 150 of them, shown in alphabetical order) is in the second dropdown menu; you can choose Fibonacci-Gann Projections Change % or Fibonacci-Gann Projections Retrace % from this list. You may also adjust the parameters for this study if you desire.

When using either Fibonacci-Gann Projections Change % or Fibonacci-Gann Retrace %, there are three numerical parameters you can change. The first, wave %, denotes the retracement percentage. The next value, Gann inc value, denotes the size of the Gann increment. The third, Gann increments, specifies the required number of bars to the right or left of the pivot peak or valley. All of these are provided with default values, so you don't need to change anything unless you want to do so.

In the example shown in Figure 7, Intel's price swings in late 2003 are tracked by the Fibonacci-Gann Projections Change % (whose parameters and last values are shown in the upper-left portion of the chart). The signal of a potential turning point is seen as the two brown squares clustered around February 23.

Figure 7: PROPHET, Fibonacci And Gann Projections. Intel's price swings in late 2003 are tracked by the Fibonacci-Gann Projections Change % (whose parameters and last values are shown in the upper-left portion of the chart). The signal of a potential turning point is seen as the two brown squares clustered around February 23.


Full access to the JavaCharts study set is available only with a premium membership to Prophet, which starts at $14.95 per month. Real-time market data is available for equities, options, and futures. A one-week trial providing immediate access to all features and studies is available from https://www.prophet.net/tasc.

--Prophet.net


GO BACK


SMARTRADER: CRACK SPREAD

The term crack spread refers to the "catalytic cracking" process used at refineries to separate crude oil into marketable products such as unleaded gasoline, heating oil, and various lesser components. The "3-2-1" crack is based on three barrels of crude oil, which will produce two barrels of unleaded gas and one barrel of heating oil. This technique is used as a theoretical refinery to determine the profitability of trading the contracts used in the spread calculation.

In this spread, we will be using three crude contracts (CL), two unleaded gas contracts (HU), and one heating oil contract (HO). Since crude is priced by the barrel, and the other contracts are priced by the gallon, it is necessary to adjust them to a 42-gallon barrel equivalent.

The SmarTrader specsheet is shown in Figure 8. First, in row 25, crude, we multiply the price of crude by three contracts. Row 26, UL_gas, multiplies the price of unleaded by two contracts, then by 42 to equate the result to a per-barrel price. In row 27, H_oil, we multiply the price of one heating oil contract by 42 to equate to a per-barrel price.

Figure 8: SMARTRADER, CRACK SPREAD. Here is the spreadsheet containing the calculations for determining the profitability of trading the contracts used in the spread calculation.


Now that all contracts are on the same price basis, row 28, product, sums the value of the refined unleaded and heating oil products. Finally, row 29, Crack, calculates the difference of the product value less the cost of the crude and divides the result by 3, reducing the spread to a per-barrel value.

Since profitability depends on the spread paying production costs before yielding a profit, a narrow spread will tend to push product prices up. A wide spread yields a high profit over production costs, causing a push in production and a supply-driven reduction in prices.

Referring to the sample crack chart shown in Figure 9, you can see that the spread value has been all over the map in recent months. As of this writing, the spread is $6.48. It will be interesting to see where prices are by the time this Traders' Tip is published.

Figure 9: SMARTRADER, CRACK SPREAD. Since profitability depends on the spread paying production costs before yielding a profit, a narrow spread will tend to push product prices up. A wide spread yields a high profit over production costs, causing a push in production and a supply-driven reduction in prices. At the time this screen capture was taken, the crack spread is $6.48. Where is it today?


Visit SmarTrader's website for more information or to download a copy of the specsheet.

--Jim Ritter, Stratagem Software
 800 779-7353 or 504 885-7353,
info@stratagem1.com, Stratagem1@aol.com
www.stratagem1.com


GO BACK


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


Return to October 2004 Contents