Gann Swing chart

Stel hier uw vragen over TA-script, of help anderen met het oplossen van hun probleem
Plaats reactie
Janus
Berichten: 1523
Lid geworden op: wo jan 30, 2008 2:07 am
Contacteer:

Gann Swing chart

Bericht door Janus »

Weer een nieuwe topic over Gann swing charts?
Ja, ik wil dit straks gaan combineren met de Point&Figure charts.
Deze twee hebben overeenkomsten, en kunnen elkaar ondersteunen bij het handelen.
Ik heb een eerste opzet bij elkaar gesprokkeld, en daarin kan de Gann swing chart worden weergegeven in de bekende zigzag vorm en in de trap-weergave.
Tevens heb ik in deze versie de Krausz HiLo activiator ingebouwd.
Ook is er de mogelijkheid om de koerscandles in te laten kleuren volgens de Gann swing, maar ook om dit te laten plaats vinden volgens het idee van Krausz, waarbij (als voorbeeld) een upswing pas groen gekleurd wordt wanneer de koers boven de vorige high uit komt (en vice versa omlaag).
Dit is versie 1.0.
Controleert u even of alles verloopt zoals dat moet, en problemen graag melden.
De volgende melding zal gaan over de overeenkomsten/verschillen met de Point&Figure methode en hoe deze elkaar kunnen ondersteunen.
De Point&Figure heb ik intussen ook al flink uitgebreid, en daar kom ik in die topic op terug.
Uiteindelijk gaan deze twee indicatoren één geheel vormen als 'methode'.
Hieronder eerst even een grafiek met wat voorbeelden van de weergave van deze Gann swing indicator.
Daarna plaats ik de code.
.
Afbeelding
.

Code: Selecteer alles

{- Filename: GannSwing_TrapOrZigZag_WithHiLoActivator -}
{ versie 1.0  01-Maart - 2026 }
{ © www.jstas.com }

// --- Constants ---------------------------------------------------------------
const
  sHelpText =
'================================================================================'+#13+
'GannSwing_TrapOrZigZag  -  Help / Uitleg'+#13+
'================================================================================'+#13+
''+#13+
'Deze indicator tekent een Gann Swing Chart in twee weergaven:'+#13+
''+#13+
'1) Trap / Kolom-weergave'+#13+
'   - De swing loopt verticaal door zolang de swing “actief” is.'+#13+
'   - Pas bij een bevestigde draai (reversal) wordt er op het draaipunt een'+#13+
'     horizontaal verbindingsstuk getekend en start de volgende kolom.'+#13+
'   - Deze weergave lijkt optisch op Point & Figure (kolommen), maar is gebaseerd'+#13+
'     op swing-reversals (Gann) en NIET op boxsize/reversal-amount zoals bij P&F.'+#13+
''+#13+
'2) ZigZag-weergave'+#13+
'   - De swing wordt als diagonale trendlijnen tussen draaipunten getekend'+#13+
'     (low -> high -> low -> high, enz.)'+#13+
'   - Met optionele “Krausz-confirm” kleurregels.'+#13+
''+#13+
'Daarnaast kan optioneel de Krausz/Gann HiLo Activator worden getekend.'+#13+
'Deze HiLo bestaat uit twee moving averages:'+#13+
'- HiMA = SMA(High, Len)'+#13+
'- LoMA = SMA(Low,  Len)'+#13+
'Regel:'+#13+
'- Bullish regime: toon LoMA'+#13+
'- Bearish regime: toon HiMA'+#13+
'Omschakeling:'+#13+
'- Naar bullish zodra Close boven HiMA komt'+#13+
'- Naar bearish zodra Close onder LoMA komt'+#13+
''+#13+
'--------------------------------------------------------------------------------'+#13+
'Belangrijkste instellingen'+#13+
'--------------------------------------------------------------------------------'+#13+
''+#13+
'Swing Count (1-bar t/m 10-bar)'+#13+
'- Bepaalt hoeveel “tegen-bars” nodig zijn om een swing als gedraaid te zien.'+#13+
'- SwingCount=1: veel swings, gevoelig (minor swings)'+#13+
'- SwingCount=2: klassiek 2-bar swing (vaak gebruikt)'+#13+
'- SwingCount=3: filtert meer ruis'+#13+
'Hoe hoger de waarde, hoe minder (maar grotere) swings.'+#13+
''+#13+
'Weergave swing-line'+#13+
'- Trap/Kolom-weergave: verticale kolommen met korte horizontale stukjes op pivots'+#13+
'- ZigZag-weergave: diagonale lijnen tussen pivot-punten'+#13+
''+#13+
'Outside bars'+#13+
'Een outside bar heeft zowel een hogere High als een lagere Low dan de vorige bar.'+#13+
'Er zijn 2 (of 3) gangbare manieren om outside bars te behandelen:'+#13+
''+#13+
'- reversal (strict):'+#13+
'  outside bar telt als “tegen-bar” en kan een reversal sneller triggeren.'+#13+
'  Dit kan bij SwingCount=2 soms tot extra wisselingen leiden.'+#13+
''+#13+
'- negeren (use next bar):'+#13+
'  outside bar wordt niet als richtinggevend voor de count gebruikt.'+#13+
''+#13+
'- close bepaalt richting:'+#13+
'  de close bepaalt of de bar als up of down meetelt. Dit geeft vaak rustiger'+#13+
'  swings bij markten met veel volatility spikes.'+#13+
''+#13+
'Breakout reversal (alleen SwingCount > 1)'+#13+
'- Extra regel: als de koers door een vorige pivot heen breekt (bijv. bij een'+#13+
'  up-swing onder de vorige pivot-low), dan wordt de reversal versneld.'+#13+
'- Praktisch: kan ervoor zorgen dat swings sneller “omklappen” bij echte breaks.'+#13+
''+#13+
'Inside bars meetellen'+#13+
'- Inside bars tellen normaal niet mee voor de swing count.'+#13+
'- Als je deze optie aanzet, kunnen inside bars toch de count laten oplopen'+#13+
'  (alleen zinvol als je een strakkere/gevoeliger swing wilt).'+#13+
''+#13+
'Kleuren van candles'+#13+
'- Indien aangezet worden koersbars ingekleurd.'+#13+
'- In de standaard swinglogica volgt de kleur meestal de actuele swingrichting.'+#13+
'- In Krausz-modus (zie hieronder) kan de candlekleur de bevestigde trend volgen.'+#13+
''+#13+
'--------------------------------------------------------------------------------'+#13+
'ZigZag “Krausz-confirm” kleurregels'+#13+
'--------------------------------------------------------------------------------'+#13+
'In de standaard ZigZag is een up-leg groen en een down-leg rood.'+#13+
'Krausz wilde strikter zijn:'+#13+
''+#13+
'- Een uptrend is pas “bevestigd” (groen) zodra de koers boven de vorige swing-high'+#13+
'  uitbreekt.'+#13+
'- Een downtrend is pas “bevestigd” (rood) zodra de koers onder de vorige swing-low'+#13+
'  uitbreekt.'+#13+
''+#13+
'Gevolg:'+#13+
'- Een tegenbeweging kan eerst de kleur van de vorige trend houden en kleurt pas'+#13+
'  om vanaf de bar waar de breakout daadwerkelijk plaatsvindt.'+#13+
'- Dit voorkomt dat kleine tegenbewegingen meteen als “trendwissel” worden gezien.'+#13+
''+#13+
'--------------------------------------------------------------------------------'+#13+
'Schaal (ScaleMin/ScaleMax)'+#13+
'--------------------------------------------------------------------------------'+#13+
'Om de indicator netjes zichtbaar te houden ongeacht het koersniveau,'+#13+
'worden twee “onzichtbare” lijnen getekend:'+#13+
'- ScaleMax = hoogste waarde in lookback + marge'+#13+
'- ScaleMin = laagste waarde in lookback - marge'+#13+
'Deze lijnen forceren de y-as schaal.'+#13+
''+#13+
'Parameters:'+#13+
'- Lookback (0=alles): hoeveel bars worden gebruikt om min/max te bepalen.'+#13+
'- Marge (%): extra ruimte boven/onder om “plakken” tegen de rand te voorkomen.'+#13+
''+#13+
'Tip:'+#13+
'- Voor indexen werkt Lookback=0 vaak prima.'+#13+
'- Voor aandelen met grote regimewissels is bijv. Lookback=250 (ongeveer 1 jaar)'+#13+
'  soms prettiger.'+#13+
''+#13+
'--------------------------------------------------------------------------------'+#13+
'Praktische tips'+#13+
'--------------------------------------------------------------------------------'+#13+
'- Begin met SwingCount=2, Outside=negeren, Breakout=aan/uit testen.'+#13+
'- Voor “rustige” swings: SwingCount verhogen (3 of 4) en outside strict uit.'+#13+
'- Voor Krausz-confirm: gebruik ZigZag + Krausz-confirm + candlekleur op trend.'+#13+
'- Combineer HiLo Activator als extra “regime filter” bovenop de swing.'+#13+
''+#13+
'--------------------------------------------------------------------------------'+#13+
'Opmerking'+#13+
'--------------------------------------------------------------------------------'+#13+
'Deze indicator is bedoeld als visualisatie van swings/trendregimes.'+#13+
'Het is geen automatisch handelssysteem en geeft geen gegarandeerde signalen.'+#13+
''+#13+
'================================================================================'+#13+
'';

Type
  TGannSwing = Record
    SwingCount  : Integer;
    UseInside   : Boolean;
    UseBreakout : Boolean;
    ColorBars   : Boolean;
    OutsideCalc : Integer;   // 0 = Outside bar telt als reversal, 1 = negeren
    OutsideKinkFix      : Boolean;
    KrauszZigZagConfirm : Boolean;
    KrauszTrend         : TSeries;   // +1 up, -1 down

    Mode        : Integer;   // 0 = Trap/Kolom, 1 = ZigZag
    UpCl        : TColor;    // kleur up-swing (swing-lijn)
    DnCl        : TColor;    // kleur down-swing (swing-lijn)
    LineWidth   : Integer;

    ShowHiLo    : Boolean;
    HiLoLen     : Integer;
    HiLoUpCl    : TColor;
    HiLoDnCl    : TColor;
    HiLoWidth   : Integer;

    BckGrndClr  : TColor;
    Base        : TSeries;   // dummy voor CreateLine
    
    ScaleLookback : Integer;   // 0 = hele historie
    ScaleMarginPct: Integer;   // extra ruimte boven/onder in %
    ScaleMinS     : TSeries;
    ScaleMaxS     : TSeries;
  End;

Var
  gs : TGannSwing;

  // --- Trap/kolom segment-opslag ---
  VIdx : array of integer;
  VY1  : array of real;
  VY2  : array of real;
  VCl  : array of TColor;

  Hx1  : array of integer;
  Hx2  : array of integer;
  Hy   : array of real;
  HCl  : array of TColor;

  VCnt : integer;
  HCnt : integer;

  // --- ZigZag punten ---
  PIdx   : array of integer;
  PPrice : array of real;
  PCnt   : integer;

// ------------------------------------------------------------

Function GetBarType(i: Integer): Integer;
Begin
  Result := 0;
  If i < 1 Then Exit;

  If (High[i] > High[i-1]) And (Low[i] > Low[i-1]) Then
    Result :=  1        // Higher
  Else
  If (High[i] < High[i-1]) And (Low[i] < Low[i-1]) Then
    Result := -1        // Lower
  Else
  If (High[i] > High[i-1]) And (Low[i] < Low[i-1]) Then
    Result :=  2        // Outside
  Else
    Result :=  0;       // Inside/neutral
End;

Procedure UserChoices();
var
helpSwingCount, helpMode, helpOutside : String;
Begin
  helpSwingCount := '1-bar'#9'2-bar'#9'3-bar'#9'4-bar'#9'5-bar'#9
                    '6-bar'#9'7-bar'#9'8-bar'#9'9-bar'#9'10-bar';
  helpMode       := 'Trap/Kolom-weergave'#9'ZigZag-weergave'#9'Krausz/Gann HiLo'
                                          #9'Trap/Kolom + HiLo'#9'Zigzag + HiLo';
  helpOutside    := 'reversal (strict)'#9'close bepaalt richting'#9'negeren = use next bar'

  gs.SwingCount  := CreateParameterSelect('Swing Count: ',helpSwingCount,1,true)+1;
  gs.Mode        := CreateParameterSelect('Weergave swing-line:',helpMode,0,True);
  gs.UseInside   := CreateParameterBoolean('Inside bars meetellen in count?', False, True);
  gs.OutsideCalc := CreateParameterSelect('Outside bars: ',helpOutside,1, True );
  gs.UseBreakout := CreateParameterBoolean('Breakout reversal (only SwingCount>1)', True, True);
  gs.OutsideKinkFix := CreateParameterBoolean('Outside bar anti-knik (High->Low in dezelfde bar)?',True, True);
  gs.KrauszZigZagConfirm := CreateParameterBoolean('ZigZag Krausz: kleur pas na bevestiging (HH/LL break)?', False, True);

  gs.ColorBars   := CreateParameterBoolean('Koersbars inkleuren volgens swing-richting?', False, True);

  gs.UpCl        := CreateParameterColor('Kleur up-swing (swing)', ClLime);
  gs.DnCl        := CreateParameterColor('Kleur down-swing (swing)', ClRed);
  gs.LineWidth   := CreateParameterInteger('Lijndikte swing-lijn', 1, 5, 2, True);

  gs.HiLoLen     := CreateParameterInteger('HiLo lengte (SMA)', 1, 100, 3, True);
  gs.HiLoUpCl    := CreateParameterColor('HiLo kleur bullish', ClAqua);
  gs.HiLoDnCl    := CreateParameterColor('HiLo kleur bearish', ClFuchsia);
  gs.HiLoWidth   := CreateParameterInteger('HiLo lijndikte', 1, 5, 1, True);
  
  gs.ScaleLookback  := CreateParameterInteger('Schaal lookback bars (0=alles)', 0, 20000, 0, True);
  gs.ScaleMarginPct := CreateParameterInteger('Schaal marge (%)', 0, 50, 3, True);

End;

Procedure Initialisaties();
Begin
  With Indicator Do
  Begin
    RequiredBars := gs.SwingCount + 2;
    ScaleRange   := srCommon;
    NewBand      := false;
    SignalSize   := 0;
    ShortName    := '';
    HelpText     := sHelpText;
  End;
End;

// ------------------------------------------------------------
// Segment/point array helpers

Procedure InitTrapArrays();
Begin
  SetArrayLength(VIdx, BarCount);
  SetArrayLength(VY1,  BarCount);
  SetArrayLength(VY2,  BarCount);
  SetArrayLength(VCl,  BarCount);

  SetArrayLength(Hx1,  BarCount);
  SetArrayLength(Hx2,  BarCount);
  SetArrayLength(Hy,   BarCount);
  SetArrayLength(HCl,  BarCount);

  VCnt := 0;
  HCnt := 0;
End;

Procedure AddVertSeg(Idx: Integer; Y1, Y2: Real; AColor: TColor);
Begin
  If (Idx < 0) Or (Idx >= BarCount) Then Exit;
  If VCnt >= BarCount Then Exit;

  VIdx[VCnt] := Idx;
  VY1[VCnt]  := Y1;
  VY2[VCnt]  := Y2;
  VCl[VCnt]  := AColor;
  VCnt := VCnt + 1;
End;

Procedure AddHorSeg(Idx1, Idx2: Integer; Y: Real; AColor: TColor);
Begin
  If (Idx1 < 0) Or (Idx1 >= BarCount) Then Exit;
  If (Idx2 < 0) Or (Idx2 >= BarCount) Then Exit;
  If HCnt >= BarCount Then Exit;

  Hx1[HCnt] := Idx1;
  Hx2[HCnt] := Idx2;
  Hy[HCnt]  := Y;
  HCl[HCnt] := AColor;
  HCnt := HCnt + 1;
End;

Procedure DrawTrapSegments();
Var k: Integer;
Begin
  If BarCount <= 0 Then Exit;

  For k := 0 To VCnt-1 Do
    With CreateTrendLine(BarPosition[VIdx[k]], VY1[k], BarPosition[VIdx[k]], VY2[k]) Do
    Begin
      Color := VCl[k];
      Width := gs.LineWidth;
    End;

  For k := 0 To HCnt-1 Do
    With CreateTrendLine(BarPosition[Hx1[k]], Hy[k], BarPosition[Hx2[k]], Hy[k]) Do
    Begin
      Color := HCl[k];
      Width := gs.LineWidth;
    End;
End;

Procedure ComputeScaleBounds(Var SMin, SMax: Real);
Var
  i, startIdx, lastIdx: Integer;
  mn, mx, rng, m: Real;
Begin
  SMin := 0;
  SMax := 0;

  If BarCount <= 0 Then Exit;

  lastIdx := BarCount - 1;

  If gs.ScaleLookback <= 0 Then
    startIdx := 0
  Else
  Begin
    startIdx := lastIdx - gs.ScaleLookback + 1;
    If startIdx < 0 Then startIdx := 0;
  End;

  mn := Low[startIdx];
  mx := High[startIdx];

  For i := startIdx To lastIdx Do
  Begin
    If Low[i]  < mn Then mn := Low[i];
    If High[i] > mx Then mx := High[i];
  End;

  rng := mx - mn;
  If rng <= 0 Then rng := 1;

  m := rng * gs.ScaleMarginPct / 100.0;

  SMin := mn - m;
  SMax := mx + m;
End;

Procedure FillScaleSeries();
Var
  i, lastIdx: Integer;
  sMin, sMax: Real;
Begin
  If BarCount <= 0 Then Exit;

  ComputeScaleBounds(sMin, sMax);

  lastIdx := BarCount - 1;
  For i := 0 To lastIdx Do
  Begin
    gs.ScaleMinS[i] := sMin;
    gs.ScaleMaxS[i] := sMax;
  End;
End;

// --- ZigZag points ---
Procedure InitPointArrays();
Begin
  SetArrayLength(PIdx,   BarCount + 10);
  SetArrayLength(PPrice, BarCount + 10);
  PCnt := 0;
End;

Procedure AddPoint(AIdx: Integer; APrice: Real);
Begin
  If (AIdx < 0) Or (AIdx >= BarCount) Then Exit;

  If PCnt > 0 Then
  Begin
    // zelfde index? overschrijf laatste punt
    If PIdx[PCnt-1] = AIdx Then
    Begin
      PPrice[PCnt-1] := APrice;
      Exit;
    End;
  End;

  PIdx[PCnt]   := AIdx;
  PPrice[PCnt] := APrice;
  PCnt := PCnt + 1;
End;

Procedure DrawTL(i1: Integer; y1: Real; i2: Integer; y2: Real; AColor: TColor);
Begin
  If (i1 < 0) Or (i2 < 0) Or (i1 >= BarCount) Or (i2 >= BarCount) Then Exit;

  With CreateTrendLine(BarPosition[i1], y1, BarPosition[i2], y2) Do
  Begin
    Color := AColor;
    Width := gs.LineWidth;
  End;
End;

Function InterpY(x1, x2: Integer; y1, y2: Real; x: Integer): Real;
Var
  denom: Integer;
Begin
  denom := (x2 - x1);
  If denom = 0 Then
    Result := y2
  Else
    Result := y1 + (y2 - y1) * (x - x1) / denom;
End;

Function FindBreakAbove(i1, i2: Integer; level: Real): Integer;
Var
  j: Integer;
Begin
  Result := -1;
  If i2 < i1 Then Exit;

  For j := i1 To i2 Do
  Begin
    If High[j] > level Then
    Begin
      Result := j;
      Exit;
    End;
  End;
End;

Function FindBreakBelow(i1, i2: Integer; level: Real): Integer;
Var
  j: Integer;
Begin
  Result := -1;
  If i2 < i1 Then Exit;

  For j := i1 To i2 Do
  Begin
    If Low[j] < level Then
    Begin
      Result := j;
      Exit;
    End;
  End;
End;

Procedure DrawZigZagClassic();
Var
  k: Integer;
  C: TColor;
Begin
  If PCnt < 2 Then Exit;

  For k := 0 To PCnt-2 Do
  Begin
    If PPrice[k+1] >= PPrice[k] Then C := gs.UpCl Else C := gs.DnCl;
    DrawTL(PIdx[k], PPrice[k], PIdx[k+1], PPrice[k+1], C);
  End;
End;

Procedure DrawZigZagKrausz();
Var
  k, sIdx, eIdx, brkIdx: Integer;
  sP, eP, yBrk: Real;

  TrendState: Integer;   // +1 = confirmed up, -1 = confirmed down
  PrevHigh  : Real;      // laatste swing-high pivot
  PrevLow   : Real;      // laatste swing-low pivot

  colBefore : TColor;
Begin
  If PCnt < 2 Then Exit;

  // init trend + thresholds uit eerste segment
  If PPrice[1] >= PPrice[0] Then
  Begin
    TrendState := 1;
    PrevLow  := PPrice[0];
    PrevHigh := PPrice[1];
  End
  Else
  Begin
    TrendState := -1;
    PrevHigh := PPrice[0];
    PrevLow  := PPrice[1];
  End;

  For k := 0 To PCnt-2 Do
  Begin
    sIdx := PIdx[k];
    eIdx := PIdx[k+1];
    sP   := PPrice[k];
    eP   := PPrice[k+1];

    // safety
    If (eIdx < sIdx) Then Continue;

    // ---------------- UP LEG ----------------
    If eP > sP Then
    Begin
      // startpivot is een low -> update last swing low
      PrevLow := sP;

      If TrendState = 1 Then
      Begin
        // al confirmed up
        DrawTL(sIdx, sP, eIdx, eP, gs.UpCl);
      End
      Else
      Begin
        // trend is down: pas groen NA break boven PrevHigh
        brkIdx := FindBreakAbove(sIdx, eIdx, PrevHigh);

        If brkIdx < 0 Then
        Begin
          // geen bevestiging -> blijft down-kleur
          DrawTL(sIdx, sP, eIdx, eP, gs.DnCl);
        End
        Else
        Begin
          yBrk := InterpY(sIdx, eIdx, sP, eP, brkIdx);

          // vóór break: down-kleur (rood)
          If brkIdx > sIdx Then
            DrawTL(sIdx, sP, brkIdx, yBrk, gs.DnCl);

          // ná break: up-kleur (groen)
          DrawTL(brkIdx, yBrk, eIdx, eP, gs.UpCl);

          TrendState := 1;
        End;
      End;

      // endpivot is high -> update last swing high
      PrevHigh := eP;
    End
    Else
    // ---------------- DOWN LEG ----------------
    If eP < sP Then
    Begin
      // startpivot is een high -> update last swing high
      PrevHigh := sP;

      If TrendState = -1 Then
      Begin
        // al confirmed down
        DrawTL(sIdx, sP, eIdx, eP, gs.DnCl);
      End
      Else
      Begin
        // trend is up: pas rood NA break onder PrevLow
        brkIdx := FindBreakBelow(sIdx, eIdx, PrevLow);

        If brkIdx < 0 Then
        Begin
          // geen bevestiging -> blijft up-kleur
          DrawTL(sIdx, sP, eIdx, eP, gs.UpCl);
        End
        Else
        Begin
          yBrk := InterpY(sIdx, eIdx, sP, eP, brkIdx);

          // vóór break: up-kleur (groen)
          If brkIdx > sIdx Then
            DrawTL(sIdx, sP, brkIdx, yBrk, gs.UpCl);

          // ná break: down-kleur (rood)
          DrawTL(brkIdx, yBrk, eIdx, eP, gs.DnCl);

          TrendState := -1;
        End;
      End;

      // endpivot is low -> update last swing low
      PrevLow := eP;
    End
    Else
    Begin
      // flat: teken met huidige trendkleur
      If TrendState = 1 Then colBefore := gs.UpCl Else colBefore := gs.DnCl;
      DrawTL(sIdx, sP, eIdx, eP, colBefore);
    End;
  End;
End;

Procedure DrawZigZag();
Begin
  If gs.KrauszZigZagConfirm Then
    DrawZigZagKrausz()
  Else
    DrawZigZagClassic();
End;


Function IsOutsideBar(idx: Integer): Boolean;
Begin
  Result := False;
  If idx < 1 Then Exit;
  Result := (High[idx] > High[idx-1]) And (Low[idx] < Low[idx-1]);
End;

Procedure FixOutsideBarKinks();
Var
  k, obIdx: Integer;
  obLow, obHigh: Real;
Begin
  // We hebben minimaal 3 punten nodig om te kunnen "schuiven"
  If PCnt < 3 Then Exit;

  // Loop over pivot k en het volgende pivot (k+1)
  For k := 0 To PCnt-2 Do
  Begin
    obIdx := PIdx[k];

    // Alleen interessant als pivot k op een outside bar ligt
    If Not IsOutsideBar(obIdx) Then Continue;

    // Case A: pivot k is een HIGH (volgende pivot is lager)
    If PPrice[k] > PPrice[k+1] Then
    Begin
      obLow := Low[obIdx];

      // Als de volgende low-pivot hoger ligt dan de outside-low,
      // verplaats die pivot naar de outside-low op dezelfde bar-index
      If PPrice[k+1] > obLow Then
      Begin
        PIdx[k+1]   := obIdx;
        PPrice[k+1] := obLow;
      End;
    End
    Else
    // Case B: pivot k is een LOW (volgende pivot is hoger)
    If PPrice[k] < PPrice[k+1] Then
    Begin
      obHigh := High[obIdx];

      // Als de volgende high-pivot lager ligt dan de outside-high,
      // verplaats die pivot naar de outside-high op dezelfde bar-index
      If PPrice[k+1] < obHigh Then
      Begin
        PIdx[k+1]   := obIdx;
        PPrice[k+1] := obHigh;
      End;
    End;
  End;
End;


// ------------------------------------------------------------
// Swing calculation: Trap/Kolom

Procedure CalcTrap();
Var
  i, LastIdx : Integer;
  Dir        : Integer;   // +1 up, -1 down
  OppCount   : Integer;

  ColIdx     : Integer;   // x van kolom (blijft gelijk tot draai)
  PivotPrice : Real;
  Extreme    : Real;
  ExtremeIdx : Integer;

  bt, cand   : Integer;
  SegColor   : TColor;
Begin
  If BarCount < 2 Then Exit;

  InitTrapArrays();
  LastIdx := BarCount - 1;

  // start-richting bepalen
  Dir := 0;
  For i := 1 To LastIdx Do
  Begin
    bt := GetBarType(i);
    If (Dir = 0) And (bt = 1)  Then Dir :=  1;
    If (Dir = 0) And (bt = -1) Then Dir := -1;
    If (Dir = 0) And (bt = 2)  Then
    Begin
      If Close[i] >= Close[i-1] Then Dir := 1 Else Dir := -1;
    End;
  End;
  If Dir = 0 Then Exit;

  ColIdx   := 0;
  OppCount := 0;
  ExtremeIdx := 0;

  If Dir = 1 Then
  Begin
    PivotPrice := Low[0];
    Extreme    := High[0];
  End
  Else
  Begin
    PivotPrice := High[0];
    Extreme    := Low[0];
  End;

  For i := 1 To LastIdx Do
  Begin
    // extreme bijwerken
    If Dir = 1 Then
    Begin
      If High[i] > Extreme Then Begin Extreme := High[i]; ExtremeIdx := i; End;
    End
    Else
    Begin
      If Low[i] < Extreme Then Begin Extreme := Low[i]; ExtremeIdx := i; End;
    End;

    bt := GetBarType(i);

    cand := 0;
    If bt =  1 Then cand :=  1;
    If bt = -1 Then cand := -1;

   { If bt = 2 Then
    Begin
      If gs.OutsideCalc = 0 Then cand := -Dir Else cand := 0;
    End;    }
    If bt = 2 Then
Begin
  Case gs.OutsideCalc Of
    0:  // reversal (strict)
        cand := -Dir;

    1:  // close bepaalt richting (voorkomt deuk in ZigZag)
        Begin
          If Close[i] > Close[i-1] Then cand :=  1
          Else
          If Close[i] < Close[i-1] Then cand := -1
          Else
            cand := 0;
        End;

    2:  // negeren
        cand := 0;
  End;
End;


    If cand = -Dir Then
      OppCount := OppCount + 1
    Else
    If (cand = 0) And gs.UseInside And (OppCount > 0) Then
      OppCount := OppCount + 1
    Else
    If cand = Dir Then
      OppCount := 0;

    If gs.UseBreakout And (gs.SwingCount > 1) Then
    Begin
      If (Dir =  1) And (Low[i]  < PivotPrice) Then OppCount := gs.SwingCount;
      If (Dir = -1) And (High[i] > PivotPrice) Then OppCount := gs.SwingCount;
    End;

    If gs.ColorBars Then
    Begin
      If Dir =  1 Then SetParentBarColor(i, gs.UpCl);
      If Dir = -1 Then SetParentBarColor(i, gs.DnCl);
    End;

    If OppCount >= gs.SwingCount Then
    Begin
      If Dir = 1 Then SegColor := gs.UpCl Else SegColor := gs.DnCl;

      // sluit kolom op ColIdx, van pivot naar (final) extreme
      AddVertSeg(ColIdx, PivotPrice, Extreme, SegColor);

      // horizontaal op draaipunt (extreme) naar nieuwe kolom-x (bar i)
      AddHorSeg(ColIdx, i, Extreme, SegColor);

      // nieuwe swing start
      PivotPrice := Extreme;
      ColIdx     := i;
      Dir        := -Dir;
      OppCount   := 0;

      // reset extreme voor nieuwe richting vanaf bar i
      If Dir = 1 Then
      Begin
        Extreme := High[i];
        If Extreme < PivotPrice Then Extreme := PivotPrice;
      End
      Else
      Begin
        Extreme := Low[i];
        If Extreme > PivotPrice Then Extreme := PivotPrice;
      End;
      ExtremeIdx := i;
    End;
  End;

  // laatste kolom tekenen
  If Dir = 1 Then SegColor := gs.UpCl Else SegColor := gs.DnCl;
  AddVertSeg(ColIdx, PivotPrice, Extreme, SegColor);
End;

// ------------------------------------------------------------
// Swing calculation: ZigZag (punten + diagonale trendlines)

Procedure CalcZigZag();
Var
  i, LastIdx : Integer;
  Dir        : Integer;   // +1 up, -1 down
  OppCount   : Integer;

  PivotPrice : Real;
  Extreme    : Real;
  ExtremeIdx : Integer;

  bt, cand   : Integer;
Begin
  If BarCount < 2 Then Exit;

  InitPointArrays();
  LastIdx := BarCount - 1;

  // start-richting bepalen
  Dir := 0;
  For i := 1 To LastIdx Do
  Begin
    bt := GetBarType(i);
    If (Dir = 0) And (bt = 1)  Then Dir :=  1;
    If (Dir = 0) And (bt = -1) Then Dir := -1;
    If (Dir = 0) And (bt = 2)  Then
    Begin
      If Close[i] >= Close[i-1] Then Dir := 1 Else Dir := -1;
    End;
  End;
  If Dir = 0 Then Exit;

  OppCount := 0;

  If Dir = 1 Then
  Begin
    PivotPrice := Low[0];
    Extreme    := High[0];
    ExtremeIdx := 0;
  End
  Else
  Begin
    PivotPrice := High[0];
    Extreme    := Low[0];
    ExtremeIdx := 0;
  End;

  // startpunt
  AddPoint(0, PivotPrice);

  For i := 1 To LastIdx Do
  Begin
    // extreme bijwerken (met index)
    If Dir = 1 Then
    Begin
      If High[i] > Extreme Then Begin Extreme := High[i]; ExtremeIdx := i; End;
    End
    Else
    Begin
      If Low[i] < Extreme Then Begin Extreme := Low[i]; ExtremeIdx := i; End;
    End;

    bt := GetBarType(i);

    cand := 0;
    If bt =  1 Then cand :=  1;
    If bt = -1 Then cand := -1;

 {   If bt = 2 Then
    Begin
      If gs.OutsideCalc = 0 Then cand := -Dir Else cand := 0;
    End;   }
    If bt = 2 Then
Begin
  Case gs.OutsideCalc Of
    0:  // reversal (strict)
        cand := -Dir;

    1:  // close bepaalt richting (voorkomt deuk in ZigZag)
        Begin
          If Close[i] > Close[i-1] Then cand :=  1
          Else
          If Close[i] < Close[i-1] Then cand := -1
          Else
            cand := 0;
        End;

    2:  // negeren
        cand := 0;
  End;
End;


    If cand = -Dir Then
      OppCount := OppCount + 1
    Else
    If (cand = 0) And gs.UseInside And (OppCount > 0) Then
      OppCount := OppCount + 1
    Else
    If cand = Dir Then
      OppCount := 0;

    If gs.UseBreakout And (gs.SwingCount > 1) Then
    Begin
      If (Dir =  1) And (Low[i]  < PivotPrice) Then OppCount := gs.SwingCount;
      If (Dir = -1) And (High[i] > PivotPrice) Then OppCount := gs.SwingCount;
    End;

    If gs.ColorBars Then
    Begin
      If Dir =  1 Then SetParentBarColor(i, gs.UpCl);
      If Dir = -1 Then SetParentBarColor(i, gs.DnCl);
    End;

    If OppCount >= gs.SwingCount Then
    Begin
      // sluit swing op het draaipunt (extreme)
      AddPoint(ExtremeIdx, Extreme);

      // draai om
      PivotPrice := Extreme;
      Dir        := -Dir;
      OppCount   := 0;

      // start nieuwe extreme vanaf bar i (zodat volgende swing kan groeien)
      If Dir = 1 Then
      Begin
        Extreme := High[i];
        If Extreme < PivotPrice Then Begin Extreme := PivotPrice; ExtremeIdx := ExtremeIdx; End
        Else ExtremeIdx := i;
      End
      Else
      Begin
        Extreme := Low[i];
        If Extreme > PivotPrice Then Begin Extreme := PivotPrice; ExtremeIdx := ExtremeIdx; End
        Else ExtremeIdx := i;
      End;
    End;
  End;

  // laatste punt toevoegen (lopende swing)
  AddPoint(ExtremeIdx, Extreme);
  
  // Anti-knik: alleen zinvol als outside bars als reversal meetellen
If gs.OutsideKinkFix And (gs.OutsideCalc = 0) Then
  FixOutsideBarKinks();

End;

// ------------------------------------------------------------
// Krausz / Gann HiLo Activator (step getekend met trendlines)

Function SMA_High(i, Len: Integer): Real;
Var
  j, n: Integer;
  s: Real;
Begin
  s := 0;
  n := 0;
  For j := 0 To Len-1 Do
  Begin
    If (i - j) < 0 Then Break;
    s := s + High[i-j];
    n := n + 1;
  End;
  If n > 0 Then Result := s / n Else Result := High[i];
End;

Function SMA_Low(i, Len: Integer): Real;
Var
  j, n: Integer;
  s: Real;
Begin
  s := 0;
  n := 0;
  For j := 0 To Len-1 Do
  Begin
    If (i - j) < 0 Then Break;
    s := s + Low[i-j];
    n := n + 1;
  End;
  If n > 0 Then Result := s / n Else Result := Low[i];
End;

Procedure DrawHiLoActivator();
Var
  i, LastIdx: Integer;
  hiMA, loMA: Real;
  state, lastState: Integer;   // +1 bullish (plot loMA), -1 bearish (plot hiMA)
  val, lastVal: Real;
  segStart: Integer;
  C: TColor;
   step : Real;
    xEnd : TDateTime;
Begin
  If (Not gs.ShowHiLo) Then Exit;
  If BarCount < 2 Then Exit;

  LastIdx := BarCount - 1;

  // init
  hiMA := SMA_High(0, gs.HiLoLen);
  loMA := SMA_Low(0,  gs.HiLoLen);

  // simpele startstate
  If Close[0] >= (hiMA + loMA) / 2 Then state := 1 Else state := -1;

  If state = 1 Then val := loMA Else val := hiMA;

  segStart  := 0;
  lastState := state;
  lastVal   := val;

  For i := 1 To LastIdx Do
  Begin
    hiMA := SMA_High(i, gs.HiLoLen);
    loMA := SMA_Low(i,  gs.HiLoLen);

    // switch-regels
    If Close[i] > hiMA Then state := 1
    Else
    If Close[i] < loMA Then state := -1
    Else
      state := lastState;

    If state = 1 Then val := loMA Else val := hiMA;

    // bij verandering: teken horizontaal + verticaal
    If (Abs(val - lastVal) > 1e-12) Or (state <> lastState) Then
    Begin
      If lastState = 1 Then C := gs.HiLoUpCl Else C := gs.HiLoDnCl;

      // horizontaal stuk
      With CreateTrendLine(BarPosition[segStart], lastVal, BarPosition[i], lastVal) Do
      Begin
        Color := C;
        Width := gs.HiLoWidth;
      End;

      // verticaal op bar i
      If state = 1 Then C := gs.HiLoUpCl Else C := gs.HiLoDnCl;
      With CreateTrendLine(BarPosition[i], lastVal, BarPosition[i], val) Do
      Begin
        Color := C;
        Width := gs.HiLoWidth;
      End;

      segStart  := i;
      lastVal   := val;
      lastState := state;
    End;
  End;


  // laatste horizontale stuk: trek door tot 1 bar NA de laatste candle
  If lastState = 1 Then C := gs.HiLoUpCl Else C := gs.HiLoDnCl;

  // 1 barbreedte (in tijd) bepalen en xEnd zetten ná de laatste bar
  step := BarPosition[LastIdx] - BarPosition[LastIdx-1];
  xEnd := BarPosition[LastIdx] + step;

  With CreateTrendLine(BarPosition[segStart], lastVal, xEnd, lastVal) Do
  Begin
    Color := C;
    Width := gs.HiLoWidth;
  End;
End;

Procedure BuildKrauszTrendSeries();
Var
  i, k, brkIdx : Integer;
  TrendState : Integer;    // +1 up, -1 down
  PrevHigh   : Real;
  PrevLow    : Real;
  sIdx, eIdx : Integer;
  sP, eP     : Real;
Begin
  If BarCount <= 0 Then Exit;

  // default: niks
  For i := 0 To BarCount-1 Do
    gs.KrauszTrend[i] := 0;

  If PCnt < 2 Then Exit;

  // init state uit eerste leg
  If PPrice[1] >= PPrice[0] Then
  Begin
    TrendState := 1;
    PrevLow  := PPrice[0];
    PrevHigh := PPrice[1];
  End
  Else
  Begin
    TrendState := -1;
    PrevHigh := PPrice[0];
    PrevLow  := PPrice[1];
  End;

  // vul vanaf bar 0 alvast met init trend
  For i := 0 To BarCount-1 Do gs.KrauszTrend[i] := TrendState;

  // loop legs
  For k := 0 To PCnt-2 Do
  Begin
    sIdx := PIdx[k];
    eIdx := PIdx[k+1];
    sP   := PPrice[k];
    eP   := PPrice[k+1];

    If eIdx < sIdx Then Continue;

    // UP leg
    If eP > sP Then
    Begin
      PrevLow := sP;

      If TrendState = -1 Then
      Begin
        // zoek eerste bar die boven PrevHigh breekt
        brkIdx := -1;
        For i := sIdx To eIdx Do
          If High[i] > PrevHigh Then Begin brkIdx := i; Break; End;

        If brkIdx >= 0 Then
        Begin
          // vanaf break: trend wordt UP
          For i := brkIdx To BarCount-1 Do
            gs.KrauszTrend[i] := 1;
          TrendState := 1;
        End;
      End;

      PrevHigh := eP;
    End
    Else
    // DOWN leg
    If eP < sP Then
    Begin
      PrevHigh := sP;

      If TrendState = 1 Then
      Begin
        // zoek eerste bar die onder PrevLow breekt
        brkIdx := -1;
        For i := sIdx To eIdx Do
          If Low[i] < PrevLow Then Begin brkIdx := i; Break; End;

        If brkIdx >= 0 Then
        Begin
          // vanaf break: trend wordt DOWN
          For i := brkIdx To BarCount-1 Do
            gs.KrauszTrend[i] := -1;
          TrendState := -1;
        End;
      End;

      PrevLow := eP;
    End;
  End;
End;

// ------------------------------------------------------------
// Main

Var
  i: Integer;
Begin
  UserChoices();
  Initialisaties();

  gs.ScaleMinS   := FillSeries(CreateSeries(BarCount), 0);
  gs.ScaleMaxS   := FillSeries(CreateSeries(BarCount), 0);
  gs.KrauszTrend := FillSeries(CreateSeries(BarCount), 0);

  FillScaleSeries();

  // CreateLine onvoorwaardelijk
  With CreateLine(gs.ScaleMaxS) do
  begin
    Color := clBlack;
  end;

  With CreateLine(gs.ScaleMinS) do
  begin
    Color := clBlack;
  end;

  // dummy series CreateLine
  If BarCount > 0 Then
    gs.Base := FillSeries(CreateSeries(BarCount), 0)
  Else
    gs.Base := CreateSeries(0);

  If BarCount > 0 Then
    For i := 0 To BarCount-1 Do
      gs.Base[i] := Close[i];

  With CreateLine(gs.Base) Do
  Begin
    Name  := 'Base (hidden)';
    Color := ClBlack;
    Visible := false;
    Width := 1;
  End;

  // Swing tekenen (mode keuze)
  If (gs.Mode = 0) or (gs.Mode = 3) Then
  Begin
    CalcTrap();
    DrawTrapSegments();
  End;

  If (gs.Mode = 1) or (gs.Mode = 4) then
  Begin
    CalcZigZag();
    If gs.KrauszZigZagConfirm Then BuildKrauszTrendSeries();
    DrawZigZag();
    If gs.ColorBars And gs.KrauszZigZagConfirm Then
    Begin
      For i := 0 To BarCount-1 Do
        Begin
          If gs.KrauszTrend[i] >= 0 Then SetParentBarColor(i, gs.UpCl)
          Else SetParentBarColor(i, gs.DnCl);
        End;
    End;
  End;

  // Optioneel: Krausz / Gann HiLo Activator
  If (gs.Mode = 2) or (gs.Mode = 3) or (gs.Mode = 4) then
  begin
    gs.ShowHiLo := true;
    DrawHiLoActivator();
  end;
End.
Vriendelijke groet,
JanS ;)
Bart
Berichten: 13
Lid geworden op: di nov 17, 2009 8:54 pm

Re: Gann Swing chart

Bericht door Bart »

Beste Janus,

Dat is weer een kunststukje aan programmeerwerk, mijn dank daarvoor.
En niet te vergeten je eerdere post van de Point & Figure-grafieken natuurlijk ook!

In de code schrijf je de tekst “Het is geen automatisch handelssysteem en kent geen gegarandeerde signalen”. Om naast de huidige visuele weergave, de werking van het systeem, de Profit/Risk te kunnen beoordelen zou het erg handig zijn om de “Trading Simulatie” en/of “Trading Simulatie Grafiek” te kunnen maken. Mogelijk is dat alsnog in te bouwen?

Nogmaals mijn dank,
Groet, Bart
Janus
Berichten: 1523
Lid geworden op: wo jan 30, 2008 2:07 am
Contacteer:

Re: Gann Swing chart

Bericht door Janus »

Dat gaat zeker nog gebeuren Bart, maar dan in combinatie met de Point & Figure grafiek. Ik heb de opzet van beide geprobeerd dusdanig op te zetten zodat ik er nog van alles bij in kan programmeren. Geduld ..
Vriendelijke groet,
JanS ;)
Janus
Berichten: 1523
Lid geworden op: wo jan 30, 2008 2:07 am
Contacteer:

Re: Gann Swing chart

Bericht door Janus »

Wanneer u een indicator in de grafiek wilt zetten, dan ziet u rechts onder in het venster de knop 'help'. Wanneer u op deze knop klikt dan verschijnt er een help-tekst. Idem wanneer u later de parameter wilt veranderen.
Hieronder even de laatste help-tekst.
.

================================================================================
GannSwing_TrapOrZigZag - Help / Uitleg
================================================================================

Deze indicator tekent een Gann Swing Chart in twee weergaven:

1) Trap / Kolom-weergave
- De swing loopt verticaal door zolang de swing “actief” is.
- Pas bij een bevestigde draai (reversal) wordt er op het draaipunt een
horizontaal verbindingsstuk getekend en start de volgende kolom.
- Deze weergave lijkt optisch op Point & Figure (kolommen), maar is gebaseerd
op swing-reversals (Gann) en NIET op boxsize/reversal-amount zoals bij P&F.

2) ZigZag-weergave
- De swing wordt als diagonale trendlijnen tussen draaipunten getekend
(low -> high -> low -> high, enz.)
- Met optionele “Krausz-confirm” kleurregels.

Daarnaast kan optioneel de Krausz/Gann HiLo Activator worden getekend.
Deze HiLo bestaat uit twee moving averages:
- HiMA = SMA(High, Len)
- LoMA = SMA(Low, Len)
Regel:
- Bullish regime: toon LoMA
- Bearish regime: toon HiMA
Omschakeling:
- Naar bullish zodra Close boven HiMA komt
- Naar bearish zodra Close onder LoMA komt

--------------------------------------------------------------------------------
Belangrijkste instellingen
--------------------------------------------------------------------------------

Swing Count (1-bar t/m 10-bar)
- Bepaalt hoeveel “tegen-bars” nodig zijn om een swing als gedraaid te zien.
- SwingCount=1: veel swings, gevoelig (minor swings)
- SwingCount=2: klassiek 2-bar swing (vaak gebruikt)
- SwingCount=3: filtert meer ruis
Hoe hoger de waarde, hoe minder (maar grotere) swings.

Weergave swing-line
- Trap/Kolom-weergave: verticale kolommen met korte horizontale stukjes op pivots
- ZigZag-weergave: diagonale lijnen tussen pivot-punten

Outside bars
Een outside bar heeft zowel een hogere High als een lagere Low dan de vorige bar.
Er zijn 2 (of 3) gangbare manieren om outside bars te behandelen:

- reversal (strict):
outside bar telt als “tegen-bar” en kan een reversal sneller triggeren.
Dit kan bij SwingCount=2 soms tot extra wisselingen leiden.

- negeren (use next bar):
outside bar wordt niet als richtinggevend voor de count gebruikt.

(Als jouw code ook de optie “close bepaalt richting” heeft:)
- close bepaalt richting:
de close bepaalt of de bar als up of down meetelt. Dit geeft vaak rustiger
swings bij markten met veel volatility spikes.

Breakout reversal (alleen SwingCount > 1)
- Extra regel: als de koers door een vorige pivot heen breekt (bijv. bij een
up-swing onder de vorige pivot-low), dan wordt de reversal versneld.
- Praktisch: kan ervoor zorgen dat swings sneller “omklappen” bij echte breaks.

Inside bars meetellen
- Inside bars tellen normaal niet mee voor de swing count.
- Als je deze optie aanzet, kunnen inside bars toch de count laten oplopen
(alleen zinvol als je een strakkere/gevoeliger swing wilt).

Kleuren van candles
- Indien aangezet worden koersbars ingekleurd.
- In de standaard swinglogica volgt de kleur meestal de actuele swingrichting.
- In Krausz-modus (zie hieronder) kan de candlekleur de bevestigde trend volgen.

--------------------------------------------------------------------------------
ZigZag “Krausz-confirm” kleurregels
--------------------------------------------------------------------------------
In de standaard ZigZag is een up-leg groen en een down-leg rood.
Krausz wilde strikter zijn:

- Een uptrend is pas “bevestigd” (groen) zodra de koers boven de vorige swing-high
uitbreekt.
- Een downtrend is pas “bevestigd” (rood) zodra de koers onder de vorige swing-low
uitbreekt.

Gevolg:
- Een tegenbeweging kan eerst de kleur van de vorige trend houden en kleurt pas
om vanaf de bar waar de breakout daadwerkelijk plaatsvindt.
- Dit voorkomt dat kleine tegenbewegingen meteen als “trendwissel” worden gezien.

--------------------------------------------------------------------------------
Schaal (ScaleMin/ScaleMax)
--------------------------------------------------------------------------------
Om de indicator netjes zichtbaar te houden (ongeacht AEX of een aandeel rond €7),
worden twee “onzichtbare” lijnen getekend:
- ScaleMax = hoogste waarde in lookback + marge
- ScaleMin = laagste waarde in lookback - marge
Deze lijnen forceren de y-as schaal.

Parameters:
- Lookback (0=alles): hoeveel bars worden gebruikt om min/max te bepalen.
- Marge (%): extra ruimte boven/onder om “plakken” tegen de rand te voorkomen.

Tip:
- Voor indexen werkt Lookback=0 vaak prima.
- Voor aandelen met grote regimewissels is bijv. Lookback=250 (ongeveer 1 jaar)
soms prettiger.

--------------------------------------------------------------------------------
Praktische tips
--------------------------------------------------------------------------------
- Begin met SwingCount=2, Outside=negeren, Breakout=aan/uit testen.
- Voor “rustige” swings: SwingCount verhogen (3 of 4) en outside strict uit.
- Voor Krausz-confirm: gebruik ZigZag + Krausz-confirm + candlekleur op trend.
- Combineer HiLo Activator als extra “regime filter” bovenop de swing.

--------------------------------------------------------------------------------
Opmerking
--------------------------------------------------------------------------------
Deze indicator is bedoeld als visualisatie van swings/trendregimes.
Het is geen automatisch handelssysteem en geeft geen gegarandeerde signalen.

================================================================================
Vriendelijke groet,
JanS ;)
Plaats reactie