App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Series/Database.pm view on Meta::CPAN
# Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2023, 2024 Kevin Ryde
# This file is part of Chart.
#
# Chart is free software; you can redistribute it and/or modify it under the
# terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3, or (at your option) any later version.
#
# Chart is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along
# with Chart. If not, see <http://www.gnu.org/licenses/>.
package App::Chart::Series::Database;
use 5.010;
use strict;
use warnings;
use Carp;
use Scalar::Util;
use App::Chart::Database;
use App::Chart::DBI;
use base 'App::Chart::Series::OHLCVI';
our $VERSION = 275;
use constant DEBUG => 0;
# %cache is keyed by symbol string, with value a App::Chart::Series::Database
# object. The value reference is weakened so it becomes undef when
# otherwise unused.
#
our %cache = ();
sub _purge_cache_on_data_changed {
my ($symbol_hash) = @_;
if (DEBUG) {
print "data-changed, purge series: ",
join (', ', grep {exists $cache{$_}} keys %$symbol_hash),"\n";
}
delete @cache{keys %$symbol_hash}; # hash slice
}
use constant::defer _init_cache => sub {
App::Chart::chart_dirbroadcast()->connect_first
('data-changed', \&_purge_cache_on_data_changed);
return;
};
sub new {
my ($class, $symbol) = @_;
if (DEBUG) { print "Series new $symbol\n"; }
my $self = $cache{$symbol};
if ($self) { return $self; }
my $base = App::Chart::DBI->read_single
('SELECT date FROM daily WHERE symbol=? ORDER BY date ASC LIMIT 1',
$symbol);
if (! $base) {
require App::Chart::TZ;
my $timezone = App::Chart::TZ->for_symbol ($symbol);
$base = $timezone->iso_date;
}
if (DEBUG) { print " base $base\n"; }
require App::Chart::Timebase::Days;
my $timebase = App::Chart::Timebase::Days->new_from_iso ($base);
$self = $class->SUPER::new (symbol => $symbol,
timebase => $timebase);
# lose any cache entries which have gone undef through weaks destroyed
delete @cache{grep {! $cache{$_}} keys %cache};
# add new entry
_init_cache();
$cache{$symbol} = $self;
Scalar::Util::weaken ($cache{$symbol});
return $self;
}
sub hi {
my ($self) = @_;
if (! exists $self->{'hi'}) {
if (DEBUG) { print "Series hi for $self->{'symbol'}\n"; }
my $date = App::Chart::DBI->read_single
('SELECT date FROM daily WHERE symbol=? ORDER BY date DESC LIMIT 1',
$self->{'symbol'});
if (DEBUG) { print " iso ",$date//'undef',"\n"; }
my $timebase = $self->{'timebase'};
$self->{'hi'} = ($date
? $timebase->from_iso_floor ($date)
: 0);
if (DEBUG) { print " hi=$self->{'hi'}\n"; }
}
return $self->{'hi'};
}
sub fill_part {
my ($self, $lo, $hi) = @_;
if (DEBUG) { print "Database $self->{'symbol'} fill_part $lo $hi\n"; }
my $dbh = App::Chart::DBI->instance;
my $timebase = $self->{'timebase'};
# date descending so first store pre-extends the respective arrays
my $sth = $dbh->prepare_cached
('SELECT date, open, high, low, close, volume, openint
FROM daily WHERE (symbol=? AND (date BETWEEN ? AND ?))
ORDER BY date DESC');
my $aref = $dbh->selectall_arrayref ($sth, undef,
$self->{'symbol'},
$timebase->to_iso ($lo),
$timebase->to_iso ($hi));
$sth->finish;
my $opens = $self->array('opens');
my $highs = $self->array('highs');
my $lows = $self->array('lows');
my $closes = $self->array('closes');
my $volumes = $self->array('volumes');
my $openints = $self->array('openints');
foreach my $row (@$aref) {
my $i = $timebase->from_iso_floor ($row->[0]);
next if ($i < 0);
if (defined $row->[1]) { $opens->[$i] = $row->[1]; }
if (defined $row->[2]) { $highs->[$i] = $row->[2]; }
if (defined $row->[3]) { $lows->[$i] = $row->[3]; }
if (defined $row->[4]) { $closes->[$i] = $row->[4]; }
if (defined $row->[5]) { $volumes->[$i] = $row->[5]; }
if (defined $row->[6]) { $openints->[$i] = $row->[6]; }
}
}
( run in 0.970 second using v1.01-cache-2.11-cpan-39bf76dae61 )