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.
.

.
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.