App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Series.pm view on Meta::CPAN
while (my ($lo, $hi) = $iter->()) {
### do: "$method $lo, $hi"
$self->$method ($lo, $hi);
foreach my $array (@arrays) {
$self->{'fill_high'} = App::Chart::max_maybe ($self->{'fill_high'},
@{$array}[$lo .. $hi]);
$self->{'fill_low'} = App::Chart::min_maybe ($self->{'fill_low'},
@{$array}[$lo .. $hi]);
}
### merge to: $got_set->as_string
}
}
sub range {
my ($self, $lo, $hi, @array_names) = @_;
### Series range: "$lo $hi of @array_names"
$lo = max ($lo, 0);
if ($hi < $lo) { return; } # eg. lo==-5 hi==-1, no data before 0
$self->fill ($lo, $hi);
my $arrays_hash = $self->{'arrays'}; # hash
if (! @array_names) {
@array_names = $self->range_default_names;
}
my @arefs = @{$arrays_hash}{@array_names}; # hash slice
require List::MoreUtils;
return List::MoreUtils::minmax
(grep {defined} map { @{$_}[$lo .. $hi] } @arefs);
}
sub range_default_names {
my ($self) = @_;
return keys %{$self->{'arrays'}}; # all arrays
}
sub linestyle {
my ($self, $newval) = @_;
if (@_ >= 2) {
$self->{'linestyle'} = $newval;
} elsif ($self->{'linestyle'}) {
return $self->{'linestyle'};
} else {
return $self->default_linestyle;
}
}
sub linestyle_class {
my ($self) = @_;
my $linestyle = $self->linestyle // return undef;
return "App::Chart::Gtk2::LineStyle::$linestyle";
}
# Return (LOWER UPPER) which is a suggested initial Y-axis page range to
# show for dates LO to HI. This is for use both with
# App::Chart::Series::OHLCVI and also any other series type without its own
# specific style.
#
# As described in "Main Window" in the manual, the aim is to scale according
# to apparent volatility, so that daily range or daily close-to-close change
# are some modest fraction of the initial page. In particular if the series
# is just going sideways it's not zoomed out to try to fill the whole
# screen. The absolute price level is not used, so say bond prices which
# hover near 100 still get scaled out to make typical daily changes of 0.1
# or whatever visible.
#
sub initial_range {
my ($self, $lo, $hi) = @_;
### Series initial_range: "$lo to $hi $self"
$lo = max ($lo, 0);
$hi = max ($hi, 0);
$self->fill ($lo, $hi);
my $highs = $self->array('highs') // [];
my $lows = $self->array('lows') // $highs;
my $values = $self->values_array;
my @diffs = ();
my $timebase = $self->timebase;
my $latest;
if ($self->units eq 'price'
&& (my $symbol = $self->symbol)) {
$latest = defined $symbol && App::Chart::Latest->get($symbol);
}
if ($latest
&& defined $latest->{'high'}
&& defined $latest->{'low'}
&& defined (my $last_iso = $latest->{'last_date'})) {
my $last_t = $timebase->from_iso_floor ($last_iso);
if ($last_t >= $lo && $last_t <= $hi) {
push @diffs, $latest->{'high'} - $latest->{'low'};
}
}
# high to low ranges in ohlcv
if ($highs != $lows) {
foreach my $i ($lo .. $hi) {
if (defined $highs->[$i] && defined $lows->[$i]) {
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;
}
( run in 0.680 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )