App-Chart

 view release on metacpan or  search on metacpan

lib/App/Chart/Series.pm  view on Meta::CPAN


  # make page no more than twice upper,lower data range, so the
  # data is not less than half the window
  { my ($l, $h) = $self->range ($lo, $hi);
    if (defined $l) {
      ### series range: "$l to $h"
      $page = min ($page, 2 * ($h - $l));
    }
  }
  ### shrink to use minimum half window: $page

  # make page no smaller than last 1/2 of data, so that's visible
  { my ($l, $h) = $self->range (CORE::int (($lo + $hi) / 2), $hi);
    if ($l) { $page = max ($page, $h - $l); }
  }
  ### expand so last half data visible: $page

  my ($l, $h);
  my $accumulate = sub {
    my ($value) = @_;
    ### accumulate: $value
    if (! defined $value) { return 1; }
    my $new_l = defined $l ? min ($value, $l) : $value;
    my $new_h = defined $h ? max ($value, $h) : $value;
    if ($new_h - $new_l <= $page) {
      $l = $new_l;
      $h = $new_h;
    }
    if (! defined $l) {
      $l = $new_l;
      $h = $new_l + $page;
    }
    return 0;
  };
  if ($latest) {
    if (defined (my $quote_iso = $latest->{'quote_date'})) {
      my $quote_t = $timebase->from_iso_floor ($quote_iso);
      if ($quote_t >= $lo && $quote_t <= $hi) {
        $accumulate->($latest->{'bid'});
        $accumulate->($latest->{'offer'});
      }
    }
    if (defined (my $last_iso = $latest->{'last_date'})) {
      my $last_t = $timebase->from_iso_floor ($last_iso);
      if ($last_t >= $lo && $last_t <= $hi) {
        $accumulate->($latest->{'last'});
        $accumulate->($latest->{'high'});
        $accumulate->($latest->{'low'});
      }
    }
  }
  for (my $i = $hi; $i >= $lo; $i--) {
    foreach my $value ($values->[$i], $highs->[$i], $lows->[$i]) {
      $accumulate->($value);
    }
  }

  my $extra = ($page - ($h - $l)) / 2;
  $l -= $extra;
  $h += $extra;
  ### initial range decided: "$l $h   $self"
  return ($l, $h);
}

# 	    # don't go below `datatype-minimum' (if present), so long as
# 	    # the actual data respects that minimum
# 	    (and-let* ((minimum    (datatype-minimum datatype))
# 		       (actual-min (apply min-maybe lst-closes))
# 		       (           (>= actual-min minimum)))
# 	      (set! lower (max lower minimum)))

sub filled_low {
  my ($self) = @_;
  return $self->{'fill_low'};
}
sub filled_high {
  my ($self) = @_;
  return $self->{'fill_high'};
}

sub find_before {
  my ($self, $before, $n) = @_;
  ### Series find_before(): "before=$before n=$n"
  if ($n <= 0) { return $before; } # asking for no points before

  my $values = $self->values_array;
  my $chunk = $n;

  my $i = $before - 1;
  for (;;) {
    $chunk *= 2;
    my $pre = $i - $chunk;
    $self->fill ($pre, $i);

    for ( ; $i >= $pre; $i--) {
      if ($i < 0) {
        ### not found, return 0
        return 0;
      }
      if (defined $values->[$i]) {
        $n--;
        if ($n <= 0) {
          ### find_before() found: $i
          return $i;
        }
      }
    }
  }
}

# return pos where there's a value somwhere $pos > $after, or $after if no more
sub find_after {
  my ($self, $after, $n) = @_;
  ### Series find_after(): "$after n=".($n//'undef')
  if ($n <= 0) { return $after; } # asking for no points after

  my $values = $self->values_array;
  my $hi = $self->hi;
  my $chunk = $n;

  my $i = $after + 1;



( run in 1.163 second using v1.01-cache-2.11-cpan-39bf76dae61 )