App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Series/Derived/ZigZag.pm view on Meta::CPAN
$self->{'filled'} = 1;
my $parent = $self->{'parent'};
my ($percent, $closes_flag) = @{$self->{'parameters'}};
$hi = $self->hi;
$parent->fill (0, $hi);
my $p = $parent->values_array;
my $ph = $closes_flag ? $p : $parent->array('highs');
my $pl = $closes_flag ? $p : $parent->array('lows');
my $s = $self->values_array;
my $factor_increase = 1 + $percent / 100;
my $factor_decrease = 1 / $factor_increase;
my $direction = sub {};
my $extreme;
my $target;
my $extreme_pos;
my ($rising, $falling);
$rising = sub {
my ($pos, $high, $low) = @_;
if (! defined $extreme || $high > $extreme) {
$extreme = $high;
$extreme_pos = $pos;
$target = $extreme * $factor_decrease;
return;
}
if ($low <= $target) {
my $ret_pos = $extreme_pos;
my $ret_val = $extreme;
$direction = $falling;
$extreme = $low;
$extreme_pos = $pos;
$target = $extreme * $factor_increase;
return $ret_pos, $ret_val;
}
return;
};
$falling = sub {
my ($pos, $high, $low) = @_;
if (! defined $extreme || $low < $extreme) {
$extreme = $low;
$extreme_pos = $pos;
$target = $extreme * $factor_increase;
return;
}
if ($low >= $target) {
my $ret_pos = $extreme_pos;
my $ret_val = $extreme;
$direction = $rising;
$extreme = $high;
$extreme_pos = $pos;
$target = $extreme * $factor_decrease;
return $ret_pos, $ret_val;
}
return;
};
# decide initial direction rising or falling
{
my $high;
my $high_pos;
my $low;
my $low_pos;
foreach my $i (0 .. $hi) {
my $value = $p->[$i] // next;
my $this_high = $ph->[$i] // $value;
my $this_low = $pl->[$i] // $value;
if (! defined $high || $this_high > $high) {
$high = $this_high;
$high_pos = $i;
}
if (! defined $low || $this_low < $low) {
$low = $this_low;
$low_pos = $i;
}
if ($high >= $low * $factor_increase) {
if ($high_pos > $low_pos) {
$direction = $rising;
$s->[0] = $s->[$low_pos] = $low;
last;
}
if ($low_pos >= $high_pos) {
$direction = $falling;
$s->[0] = $s->[$high_pos] = $high;
last;
}
}
}
}
foreach my $i ($lo .. $hi) {
my $value = $p->[$i] // next;
my ($pos, $val) = $direction->($i,
$ph->[$i] // $value,
$pl->[$i] // $value);
if (defined $pos) {
$s->[$pos] = $val;
}
}
if ($extreme_pos) {
$s->[$extreme_pos] = $s->[$hi] = $extreme;
}
}
1;
__END__
# =head1 NAME
#
# App::Chart::Series::Derived::ZigZag -- zig zag indicator
#
# =head1 SYNOPSIS
#
( run in 2.117 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )