# Finance::Quote Perl module to retrieve prices of funds from morningstar.de # Copyright (C) 2020 Matthias Merz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA package Finance::Quote::Morningstarde; use strict; use HTML::TreeBuilder::XPath; use POSIX qw(strftime); my $agent_string = 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0'; sub baseurl { return 'https://www.morningstar.de/de/funds/snapshot/snapshot.aspx?id='; } my %idmap = ( '986855' => 'F0GBR04DI1', 'lu0048293285' => 'F0GBR04DI1', '974119' => 'F0GBR04AR8', 'lu0055631609' => 'F0GBR04AR8', ); sub methods {return ('morningstarde' => \&morningstarde);} { my @labels = ('name', 'date', 'nav', 'currency'); sub labels { return (morningstarde => \@labels); } } sub get_stock_url { my $stock_symbol = shift; # check ID-map for symbol, otherwise interpret as an ID my $id = $idmap{lc($stock_symbol)}; if (defined($id)) { return baseurl() . $id; } else { return baseurl() . $stock_symbol; }; } sub morningstarde { my $quoter = shift; # The Finance::Quote object. my @stocks = @_; my $ua = $quoter->user_agent(); $ua->agent($agent_string); my %info; foreach my $stock (@stocks) { my $get_url = get_stock_url($stock); if (!defined($get_url) || length($get_url) == 0) { $info{$stock,"errormsg"} = "undefined URL"; next; } my $response = $ua->get($get_url . "&search_value=" . $stock); #print $response->content, "\n"; $info{$stock,"success"} = 0; if (!$response -> is_success()) { $info{$stock,"errormsg"} = "HTTP failure"; } else { $info{$stock,"success"} = 1; $info{$stock,'symbol'} = $stock; my $parser = HTML::TreeBuilder::XPath->new_from_content($response->decoded_content); my $namestr = $parser->findnodes('//div[@id="snapshotTitleDiv"]//h1'); if (defined($namestr)) { $info{$stock,'name'} = $namestr; }; my $row = 2; while (!defined($info{$stock,'currency'}) && $row <=10) { my $pricestr = $parser->findnodes('//div[@id="overviewQuickstatsDiv"]//tr[' . $row . ']/td[3]'); if (defined($pricestr)) { my @splitvals = ( $pricestr =~ /(\w+).([0-9,.]+)/g); if (@splitvals) { $info{$stock,'currency'} = $splitvals[0]; my $converted_price = $splitvals[1]; $converted_price =~ s/\.//g; $converted_price =~ s/,/./g; $info{$stock,'nav'} = $converted_price; } # if it does not look like a currency, try next row if ($info{$stock,'currency'} !~ /\w{2,3}/) { undef $info{$stock,'currency'}; } $row++; }; } my $datestr = $parser->findnodes('//div[@id="overviewQuickstatsDiv"]//tr[2]/td[1]//span'); if (defined($datestr)) { my $tradedate = $datestr; $tradedate =~ s/.*\|\s*(\d\d.*) $/$1/g; if (length($tradedate) < 10) { $tradedate = POSIX::strftime( '%d.%m.%Y', localtime()); } $info{$stock,'date'} = $tradedate; $quoter->store_date(\%info, $stock, {eurodate => $tradedate}); }; $info{$stock,'timezone'} = 'Europe/Berlin'; #$info{$stock,'currency'} = 'EUR'; } } return wantarray ? %info : \%info; } 1; =head1 NAME Finance::Quote::Morningstarde - Obtain fonds quotes from Morningstar.de. =head1 SYNOPSIS use Finance::Quote; $q = Finance::Quote->new("Morningstarde"); %info = Finance::Quote->fetch("morningstarde","A0M9A2"); =head1 DESCRIPTION This module obtains fund prices from Morningstar.de, https://www.morningstar.de/. =head1 LABELS RETURNED The following labels may be returned by Finance::Quote::Morningstarde: name, date, price, last, method. =head1 SEE ALSO https://www.morningstar.de/ Finance::Quote; =cut