App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Suffix/MLC.pm view on Meta::CPAN
# This is only based on observation, in the morning it seems to be not the
# previous weekday but the one before that, and Thursday on a weekend.
# Don't know what time of day it ticks over, assume midnight for now.
#
sub available_tdate {
return App::Chart::Download::tdate_today_after
(23,59, App::Chart::TZ->sydney)
- 1;
}
# Sample url:
# https://www.mlc.com.au/masterkeyWeb/execute/UnitPricesWQO?openAgent&reporttype=HistoricalDateRange&product=MasterKey%20Allocated%20Pension%20%28Five%20Star%29&fund=MLC%20MasterKey%20Horizon%201%20-%20Bond%20Portfolio&begindate=07/01/2007&enddate=07...
#
# In the past it was plain http:
# http://www.mlc.com.au/masterkeyWeb/execute/UnitPricesWQO?openAgent&reporttype=HistoricalDateRange&product=MasterKey%20Superannuation%20%28Gold%20Star%29&fund=Property%20Securities%20Fund&begindate=19/07/2003&enddate=19/07/2004&
#
sub url_func {
my ($symbol, $lo, $hi) = @_;
my ($lo_year, $lo_month, $lo_day) = App::Chart::tdate_to_ymd ($lo);
my ($hi_year, $hi_month, $hi_day) = App::Chart::tdate_to_ymd ($hi);
my ($fund, $product) = split /,/, App::Chart::symbol_sans_suffix ($symbol);
return sprintf ('https://www.mlc.com.au/masterkeyWeb/execute/UnitPricesWQO?openAgent&reporttype=HistoricalDateRange&product=%s&fund=%s&begindate=%02d/%02d/%04d&enddate=%02d/%02d/%04d&',
URI::Escape::uri_escape ($product),
URI::Escape::uri_escape ($fund),
$lo_day, $lo_month, $lo_year,
$hi_day, $hi_month, $hi_year);
}
# Lines like:
# historicalProduct1funds[1]="MLC Property Securities Fund,MasterKey Superannuation (Gold Star),29 March 2007,64.71567,0.00000";
#
sub parse {
my ($symbol, $resp) = @_;
my $content = $resp->decoded_content(raise_error=>1);
my @data = ();
my $h = { source => __PACKAGE__,
resp => $resp,
currency => 'AUD',
data => \@data };
while ($content =~ /^historicalProduct1funds.*=\"(.*)\"/mg) {
### $&
my ($fund, $product, $date, $price) = split /,/, $1;
# skip historicalProduct1funds[0]="All Funds" bit
if (! $product) { next; }
my ($year, $month, $day) = Date::Calc::Decode_Date_EU ($date);
# skip weekends in some old data
next if (ymd_is_weekend ($year, $month, $day));
$date = App::Chart::ymd_to_iso ($year, $month, $day);
push @data, { symbol => $fund . ',' . $product . '.MLC',
date => $date,
close => $price };
}
return $h;
}
sub validate_symbol {
my ($symbol) = @_;
if ($symbol !~ /,/) {
print __x("MLC: invalid symbol, should be \"Fund,Product.MLC\": {symbol}\n",
symbol => $symbol);
return 0;
}
return 1;
}
#------------------------------------------------------------------------------
# latest
#
# The approach here is to download the latest price the same as for the
# database above, getting the latest and second latest, so as to calculate a
# "change", and back a few extra days to allow for public holidays.
#
# There's a single download of latest prices for all funds and products. If
# $symbol_list was big then it might be worth doing that instead of
# individual downloads, but not sure if a set of immediately preceding
# prices would be available to make the "change" amount. In any case for
# now it's probably unlikely there'll be many funds in the watchlist that
# are not in the database.
#
App::Chart::LatestHandler->new
(pred => $pred,
proc => \&latest,
max_symbols => 1,
available_tdate => \&available_tdate);
sub latest {
my ($symbol_list) = @_;
my $symbol = $symbol_list->[0];
if (! validate_symbol ($symbol)) { return; }
my $avail_tdate = available_tdate();
my $url = url_func ($symbol, $avail_tdate-3, $avail_tdate+1);
my $resp = App::Chart::Download->get ($url);
App::Chart::Download::write_latest_group (parse ($symbol, $resp));
}
#-----------------------------------------------------------------------------
# generic helpers
sub ymd_is_weekend {
my ($year, $month, $day) = @_;
return (Date::Calc::Day_of_Week ($year, $month, $day) >= 6); # 6 or 7
}
1;
__END__
( run in 0.782 second using v1.01-cache-2.11-cpan-39bf76dae61 )