App-Chart

 view release on metacpan or  search on metacpan

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

        my $diff = CORE::abs ($highs->[$i] - $lows->[$i]);
        if ($diff != 0) {
          push @diffs, $diff;
        }
      }
    }
  }

  # ENHANCE-ME: look at all parts of a multi-line like macd, bollinger,
  # guppy, etc
  #     (if (= 2 (array-rank array))
  # 	# macd, not quite right
  # 	(set! array (make-shared-array-column array 0)))

  # close to close ranges
  {
    my $prev;
    foreach my $i ($lo .. $hi) {
      my $value = $values->[$i];
      if (! defined $value) { next; }

      if (defined $prev) {
        my $diff = CORE::abs ($value - $prev);
        if ($diff != 0) {
          push @diffs, $diff;
        }
      }
      $prev = $value;
    }
  }

  if (! @diffs) {
    ### no diffs for initial range: "$lo $hi"
    my ($l, $h) = $self->range ($lo, $hi);
    if (defined $l) {
      # for just a single close value pretend 20% around the value
      return $h * 0.8, $l / 0.8;
    }
    return;
  }

  # page will show 25x the median range
  @diffs = sort {$a <=> $b} @diffs;
  my $page = 25 * $diffs[CORE::int ($#diffs / 2)];
  ### initial page by: "25*median is $page"

  # 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 {



( run in 1.076 second using v1.01-cache-2.11-cpan-5623c5533a1 )