# ジグザグ ZIGZAG # 引数 値幅 値 ($PriceRange, \@High, \@Low) # 戻り値 ジグザグ (@zigzag) sub ZIGZAG{ my ($PriceRange, $High, $Low) = @_; my @zigzag = (); my $Highest = 0; my $Lowest = 0; my $PrevHighest = 0; my $PrevLowest = 0; my $BuyOnReaction = 0; my $SellingOnRally = 0; my $X = 0; my $X1 = 0; my $X2 = 0; my $PrevX1 = 0; my $Y1 = 0; my $Y2 = 0; my $Up = 1; my $Down = 1; my $Check = 0; my $BuyOnReactionFlag = 0; my $SellingOnRallyFlag = 0; my $ReactionRally = 3; my $count = @$High - 1; # 値幅と配列数の確認 if(($PriceRange <= 0) || ($count < 0) || (@$High != @$Low)){ return 0; } $Highest = $$High[$count]; $Lowest = $$Low[$count]; $X2 = $X = $count; $X1 = $X2 - 1; # 計算 for(my $i = $count - 1; $i >= 0; $i--){ if($Up == 1){ # 高値更新 if($Highest <= $$High[$i]){ $PrevHighest = $Highest; $PrevX1 = $X1; $Highest = $$High[$i]; $X1 = $i; } # 最高値==高値ならトレンドを反転させない if(($X1 != $i) && (($Highest - $PriceRange) >= $$Low[$i])){ # Flag $Check = 1; } if($Check != 1){ # 値幅以上の動きがあるなら if(($Highest - $Lowest) >= $PriceRange){ # 最高値から(1 / $ReactionRally)下げたら押し目と判断 if(($X1 != $i) && (($Highest - (($Highest - $Lowest) / $ReactionRally)) >= $$Low[$i]) && ($BuyOnReaction >= $$Low[$i])){ $BuyOnReaction = $$Low[$i]; $X = $i; } if(($X1 < $X) && ($X < $PrevX1)){ # Flag $Check = 1; $BuyOnReactionFlag = 1; } }else { $BuyOnReaction = $Highest; } } }elsif($Down == 1){ # 安値更新 if($Lowest >= $$Low[$i]){ $PrevLowest = $Lowest; $PrevX1 = $X1; $Lowest = $$Low[$i]; $X1 = $i; } # 最安値==安値ならトレンドを反転させない if(($X1 != $i) && (($Lowest + $PriceRange) <= $$High[$i])){ # Flag $Check = 1; } if($Check != 1){ # 値幅以上の動きがあるなら if(($Highest - $Lowest) >= $PriceRange){ # 最安値から(1 / $ReactionRally)上げたら戻りと判断 if(($X1 != $i) && (($Lowest + (($Highest - $Lowest) / $ReactionRally)) <= $$High[$i]) && ($BuyOnReaction <= $$High[$i])){ $SellingOnRally = $$High[$i]; $X = $i; } if(($X1 < $X) && ($X < $PrevX1)){ # Flag $Check = 1; $SellingOnRallyFlag = 1; } }else { $SellingOnRally = $Lowest; } } } if($Check == 1){ my @Line = (); my $Start = 0; if($Up == 1){ if($BuyOnReactionFlag != 1){ # 上昇トレンドの終わり $Y1 = $Highest; $Y2 = $Lowest; @Line = &LINE($X1, $X2, $Y1, $Y2); # 下降トレンドへ $Lowest = $$Low[$i]; # Flag $Up = 0; $Down = 1; # 配列を開始位置 $Start = $X1; # 最高値・最安値の位置 $X2 = $X1; $X1 = $i; $X = $X1; }else { # 押し目 $Y1 = $PrevHighest; $Y2 = $Lowest; my @tmp1 = &LINE($PrevX1, $X2, $Y1, $Y2); $Y1 = $BuyOnReaction; $Y2 = $PrevHighest; my @tmp2 = &LINE($X, $PrevX1, $Y1, $Y2); # 配列のコピー @Line = (@tmp2, @tmp1); $Lowest = $BuyOnReaction; # 配列の終点 $X2 = $X; # Flag $BuyOnReactionFlag = 0; # 配列のコピー 開始位置 $Start = $X; } }elsif ($Down == 1){ if($SellingOnRallyFlag != 1){ # 下降トレンドの終わり $Y1 = $Lowest; $Y2 = $Highest; @Line = &LINE($X1, $X2, $Y1, $Y2); # 上昇トレンドへ $Highest = $$High[$i]; # Flag $Up = 1; $Down = 0; # 配列を開始位置 $Start = $X1; # 最高値・最安値の位置 $X2 = $X1; $X1 = $i; $X = $X1; }else { # 戻り $Y1 = $PrevLowest; $Y2 = $Highest; my @tmp1 = &LINE($PrevX1, $X2, $Y1, $Y2); $Y1 = $SellingOnRally; $Y2 = $PrevLowest; my @tmp2 = &LINE($X, $PrevX1, $Y1, $Y2); # 配列のコピー @Line = (@tmp2, @tmp1); $Highest = $SellingOnRally; # 配列の終点 $X2 = $X; # Flag $SellingOnRallyFlag = 0; # 配列のコピー 開始位置 $Start = $X; } } for(my $j = 0; $j < @Line; $j++){ # ジグザグ ZIGZAG $zigzag[$Start + $j] = $Line[$j]; } # Flag $Check = 0; } } # 残り my @Line = (); if($Up == 1){ # 上昇中 @Line = &LINE(0, $X2, $$High[0], $Lowest); }else { if($Down == 1){ # 下降中 @Line = &LINE(0, $X2, $$Low[0], $Highest); } } for(my $i = 0; $i < @Line; $i++){ # ジグザグ ZIGZAG $zigzag[$i] = $Line[$i]; } return @zigzag; } # 直線 # 引数 値幅 値 ($X1, $X2, $Y1, $Y2) # 戻り値 直線 (@line) sub LINE { my ($X1, $X2, $Y1, $Y2) = @_; my @line = (); my $m = ($Y2 - $Y1) / ($X2 - $X1); my $diff = $X2 - $X1; for(my $x = 0; $x < $diff; $x++){ $line[$x] = ($m * $x) + $Y1; } return @line; }