1#!/usr/bin/perl -w 2# 3# Copyright (C) 2019, Jalon Avens 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18# 02110-1301, USA 19 20package Finance::Quote::MorningstarAU; 21 22use strict; 23use warnings; 24 25use constant DEBUG => $ENV{DEBUG}; 26use if DEBUG, 'Smart::Comments'; 27 28use JSON; 29use Web::Scraper; 30 31our $VERSION = '1.51'; # VERSION 32 33sub methods { 34 return (aufunds => \&morningstarau, morningstarau => \&morningstarau,); 35} 36 37sub labels { 38 my @labels = qw/currency date isodate method name price symbol/; 39 return (aufund => \@labels, morningstarau => \@labels); 40} 41 42sub morningstarau { 43 my $quoter = shift; 44 my @symbols = @_; 45 my $ua = $quoter->user_agent(); 46 47 return unless @symbols; 48 49 my %info; 50 51 foreach my $symbol (@symbols) { 52 eval { 53 my $lookup = "https://www.morningstar.com.au/Ausearch/SecurityCodeAutoLookup?q=$symbol"; 54 my $reply = $ua->get($lookup); 55 56 die "Failed to find APIR $symbol" unless $reply->code == 200; 57 58 my $json_data = JSON::decode_json $reply->content; 59 60 ### MorningstarAU lookup: $json_data 61 62 die "Failed to find unique APIR $symbol" unless $json_data and $json_data->{hits}->{total} == 1; 63 64 my $id = $json_data->{hits}->{hits}[0]->{_source}->{Symbol}; 65 66 ### MorningstarAU input: $symbol 67 ### MorningstarAU id : $id 68 69 my $url = "https://www.morningstar.com.au/Funds/FundReport/$id"; 70 $reply = $ua->get($url); 71 72 die "Failed to fetch quote for $symbol using id $id" unless $reply->code == 200; 73 74 my $processor = scraper { 75 process 'div#maincontent h1.RecentHeading', 'name' => ['TEXT', sub {s/^\s*|\s*$//g}]; 76 process 'h3 + p.fundreportsubheading', 'date[]' => ['TEXT', qr/^as at ([0-9]{1,2} [A-Za-z]{3} [0-9]{4})/]; 77 process 'table.tablefundreport td', 'table[]' => ['TEXT', sub {s/\s//g}]; 78 }; 79 80 my $data = $processor->scrape($reply); 81 82 ### data: $data 83 84 my %table = @{$data->{table}}; 85 86 die "Mismatch symbol $symbol to APIR Code $table{APIRCode}" unless $symbol eq $table{APIRCode}; 87 88 $info{$symbol, 'success'} = 1; 89 $info{$symbol, 'currency'} = $table{BaseCurrency} eq '$A' ? 'AUD' : $table{BaseCurrency}; 90 91 my @dates = grep defined, @{$data->{date}}; 92 $quoter->store_date(\%info, $symbol, {'eurodate' => $dates[-1]}); 93 94 $info{$symbol, 'method'} = 'morningstarau'; 95 $info{$symbol, 'name'} = $data->{name}; 96 $info{$symbol, 'price'} = $table{'ExitPrice$'}; 97 $info{$symbol, 'symbol'} = $table{APIRCode}; 98 }; 99 100 if ($@) { 101 chomp($@); 102 ### error: $@ 103 104 $info{$symbol, 'success'} = 0; 105 $info{$symbol, 'errormsg'} = $@; 106 } 107 } 108 109 return wantarray() ? %info : \%info; 110} 111 1121; 113 114=head1 NAME 115 116Finance::Quote::MorningstarAU - Obtain Australian managed fund quotes from morningstar.com.au 117 118=head1 SYNOPSIS 119 120 $q = Finance::Quote->new; 121 122 %info = Finance::Quote->fetch("morningstarau","<APIR> ..."); # Only query morningstar.com.au using APIRs 123 %info = Finance::Quote->fetch("aufunds","<APIR> ..."); # Failover to other sources 124 125=head1 DESCRIPTION 126 127This module fetches information from the MorningStar Funds service 128https://morningstar.com.au to provide quotes on Australian managed funds in 129AUD. 130 131Funds are identified by their APIR code. 132 133This module is loaded by default on a Finance::Quote object. It's also possible 134to load it explicitly by placing "morningstarau" in the argument list to 135Finance::Quote->new(). 136 137=head2 Managed Funds 138 139This module provides both the "morningstarau" and "aufunds" fetch methods for 140fetching Australian funds prices from morningstar.com.au. Please use the 141"aufunds" fetch method if you wish to have failover with future sources for of 142Ausralian fund quotations which might be provided by other Finance::Quote 143modules. Using the "morningstarau" method will guarantee that your information 144only comes from the morningstar.com.au website. 145 146=head1 LABELS RETURNED 147 148The following labels may be returned by 149Finance::Quote::MorningstarAU::morningstarau: 150 151 currency, date, isodate, method, name, price, symbol 152 153=head1 SEE ALSO 154 155Morningstart Australia website https://morningstar.com.au 156 157=head1 AUTHOR 158 159Jalon Avens & others 160 161=head1 COPYRIGHT AND LICENSE 162 163Copyright (C) 2019 by Jalon Avens 164 165This program is free software; you can redistribute it and/or modify 166it under the terms of the GNU General Public License as published by 167the Free Software Foundation; either version 2 of the License, or (at 168your option) any later version. 169 170=cut 171