App-idxdb
view release on metacpan or search on metacpan
lib/App/idxdb.pm view on Meta::CPAN
v => 1.1,
summary => 'Show data from daily stock/trading summary',
args => {
%arg0_stocks,
%argsopt_filter_date,
%argopt_fields_daily,
total => {
schema => 'bool*',
},
%argopt_graph,
},
};
sub daily {
my %args = @_;
my $stocks = $args{stocks};
my $fields = $args{fields};
my $state = _init(\%args, 'ro');
my $dbh = $state->{dbh};
my @wheres;
my @binds;
push @wheres, "StockCode IN (".join(",", map {$dbh->quote($_)} @$stocks).")";
if ($args{date_start}) {
push @wheres, "date >= '".$args{date_start}->ymd."'";
}
if ($args{date_end}) {
push @wheres, "date <= '".$args{date_end}->ymd."'";
}
my $sth = $dbh->prepare("SELECT * FROM daily_trading_summary WHERE ".join(" AND ", @wheres)." ORDER BY date,StockCode");
$sth->execute(@binds);
my %stock_rows; # key=stock code, value[row, ...]
my %stock_totals; # key=stock code, value={ field=>TOTAL, ... }
my ($mindate, $maxdate);
while (my $row = $sth->fetchrow_hashref) {
my $code = $row->{StockCode};
$mindate //= $row->{Date};
$maxdate = $row->{Date};
$stock_rows{$code} //= [];
# calculated fields
$row->{ForeignNetBuy} = $row->{ForeignBuy} - $row->{ForeignSell};
$row->{AccumForeignBuy} = (@{ $stock_rows{$code} } ? $stock_rows{$code}[-1]{AccumForeignBuy} : 0) + $row->{ForeignBuy} if grep {$_ eq 'AccumForeignBuy'} @$fields;
$row->{AccumForeignSell} = (@{ $stock_rows{$code} } ? $stock_rows{$code}[-1]{AccumForeignSell} : 0) + $row->{ForeignSell} if grep {$_ eq 'AccumForeignSell'} @$fields;
$row->{AccumForeignNetBuy} = (@{ $stock_rows{$code} } ? $stock_rows{$code}[-1]{AccumForeignNetBuy} : 0) + $row->{ForeignNetBuy} if grep {$_ eq 'AccumForeignNetBuy'} @$fields;
# calculate total
if ($args{total}) {
for my $f (@daily_fields) {
my $spec = $daily_fields{$f};
next unless $spec->{type} =~ /^(volume|money|freq)$/;
$stock_totals{$code}{$f} += $row->{$f} if defined $row->{$f};
}
}
delete $row->{StockCode};
delete $row->{persen};
delete $row->{percentage};
delete $row->{ctime};
delete $row->{mtime};
for my $f (@daily_fields) { delete $row->{$f} unless (grep {$_ eq $f} @$fields) }
push @{ $stock_rows{$code} }, $row;
}
if ($args{graph}) {
require Chart::Gnuplot;
require Color::RGB::Util;
require ColorTheme::Distinct::WhiteBG;
require File::Temp;
my ($tempfh, $tempfilename) = File::Temp::tempfile();
$tempfilename .= ".png";
my $theme = ColorTheme::Distinct::WhiteBG->new;
my @colors = map { '#'.$theme->get_item_color($_) } ($theme->list_items);
my $chart = Chart::Gnuplot->new(
output => $tempfilename,
title => join(",", @$fields)." of ".join(",",@$stocks)." from $mindate to $maxdate",
xlabel => 'date',
ylabel => $fields->[0],
(@$fields > 1 ? (y2label =>
$fields->[1] .
(@$fields > 2 ? ", $fields->[2]" : "") .
(@$fields > 3 ? ", ...":"")) : ()),
timeaxis => 'x',
xtics => {labelfmt=>'%Y-%m-%d', rotate=>"30 right"},
#yrange => [0, 5000],
#y2range => [-0, 1000_000_000],
ytics => {mirror=>'off'}, # no effect?
y2tics => {mirror=>'off'}, # no effect?
);
my $i = -1;
my @datasets;
STOCK:
for my $stock (@$stocks) {
FIELD:
for my $field (@$fields) {
$i++;
push @datasets, Chart::Gnuplot::DataSet->new(
xdata => [map { $_->{Date} } @{ $stock_rows{$stock} }],
ydata => [map { $_->{$field} } @{ $stock_rows{$stock} }],
timefmt => '%Y-%m-%d',
title => "$stock.$field",
color => $colors[$i],
style => 'lines',
($i ? (axes => "x1y2") : ()),
);
}
}
$chart->plot2d(@datasets);
require Browser::Open;
Browser::Open::open_browser("file:$tempfilename");
return [200];
}
( run in 1.488 second using v1.01-cache-2.11-cpan-d8267643d1d )