###########################################
package CachedQuote;
# Cache stock closing prices
# Mike Schilli, 2007 (
[email protected])
###########################################
use strict;
use warnings;
use Cache::Historical;
use Log::Log4perl qw(:easy);
use Finance::QuoteHist::Yahoo;
###########################################
sub new {
###########################################
my($class, %options) = @_;
my $self = {
file => "/tmp/cached-quote.dat",
%options,
};
$self->{cache} = Cache::Historical->new(
sqlite_file => $self->{file});
bless $self, $class;
}
###########################################
sub quote {
###########################################
my($self, $date, $key) = @_;
my $quote = $self->{cache}->get(
$date, $key);
return $quote if defined $quote;
$self->quote_refresh( $date, $key );
return $self->{cache}->get_interpolated(
$date, $key);
}
###########################################
sub quote_refresh {
###########################################
my($self, $date, $symbol) = @_;
my($from, $to) =
$self->{cache}->time_range($symbol);
my $upd = $self->{cache}->
since_last_update($symbol);
# Date available, no refresh
if(defined $to and defined $from and
$date <= $to and $date >= $from) {
DEBUG "Date within, no refresh";
return 1;
}
if(defined $date and defined $to and
defined $upd and $date > $to and
$upd->delta_days < 1) {
DEBUG "Date ($date) above cached",
" range ($from-$to), but cache ",
"is up-to-date.";
return 1;
}
my $start = $date->clone->subtract(
years => 1 );
if(defined $start and defined $from and
$start > $from and $to > $start) {
# no need to refresh old data
$start = $to;
}
$self->quotes_fetch(
$start,
DateTime->today(),
$symbol);
}
###########################################
sub quotes_fetch {
###########################################
my($self, $start, $end, $symbol) = @_;
DEBUG "Refreshing $symbol ",
"($start - $end)";
my $q = Finance::QuoteHist::Yahoo->new(
symbols => [$symbol],
start_date => date_format($start),
end_date => date_format($end),
);
foreach my $row ($q->quotes()) {
my($symbol, $date, $open, $high, $low,
$close, $volume) = @$row;
$self->{cache}->set( dt_parse($date),
$symbol, $close );
}
}
###########################################
sub date_format {
###########################################
my($dt) = @_;
return $dt->strftime("%m/%d/%Y");
}
###########################################
sub dt_parse {
###########################################
my($string) = @_;
my $fmt =
DateTime::Format::Strptime->new(
pattern => "%Y/%m/%d");
$fmt->parse_datetime($string);
}
1;