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