File Coverage

blib/lib/Finance/Quote/Fondsweb.pm
Criterion Covered Total %
statement 14 61 22.9
branch 0 6 0.0
condition n/a
subroutine 6 8 75.0
pod 0 4 0.0
total 20 79 25.3


line stmt bran cond sub pod time code
1             #
2             # Copyright (C) 2018, Diego Marcolungo
3             #
4             # This program is free software: you can redistribute it and/or modify
5             # it under the terms of the GNU General Public License as published by
6             # the Free Software Foundation, either version 3 of the License, or
7             # (at your option) any later version.
8             #
9             # This program is distributed in the hope that it will be useful,
10             # but WITHOUT ANY WARRANTY; without even the implied warranty of
11             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12             # GNU General Public License for more details.
13             #
14             # You should have received a copy of the GNU General Public License
15             # along with this program. If not, see <http://www.gnu.org/licenses/>.
16              
17             package Finance::Quote::Fondsweb;
18              
19              
20 5     5   2555 use warnings;
  5         10  
  5         206  
21 5     5   31 use strict;
  5         9  
  5         103  
22              
23 5     5   25 use HTTP::Request::Common;
  5         12  
  5         405  
24 5     5   40 use HTML::TreeBuilder::XPath;
  5         10  
  5         92  
25              
26             our $VERSION = '1.58'; # VERSION
27              
28             our $FONDSWEB_URL = "https://www.fondsweb.com/de/";
29              
30 5     5 0 26 sub methods { return ( fondsweb => \&fondsweb ); }
31              
32             {
33             my @labels = qw/name symbol isin date isodate year_range nav last price currency source method type/;
34 5     5 0 16 sub labels { return (fondsweb => \@labels); }
35             }
36              
37             # 123.456.789,00 -> 123456789.00
38             sub decimalPeriod {
39 0     0 0   my $value = shift;
40              
41 0           $value =~ s/[.,]([0-9]+)$/#$1/; # temporarily replace final seperator with #
42 0           $value =~ s/[.,]//g; # remove all other seperators
43 0           $value =~ s/#/./; # replace # with .
44              
45 0           return $value;
46             }
47              
48             sub fondsweb {
49            
50 0     0 0   my $quoter = shift;
51 0           my @symbols = @_;
52 0           my $te = HTML::TableExtract->new( depth => 0, count => 6 );
53 0           my %info;
54            
55             # Iterate over each symbol
56 0           foreach my $symbol (@symbols) {
57 0           my $tree = HTML::TreeBuilder::XPath->new;
58 0           my $url = $FONDSWEB_URL . $symbol;
59             #~ debug_ua( $quoter->user_agent );
60            
61             # The site check the user agent
62 0           $quoter->user_agent->agent("Mozilla/5.0 (X11; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0");
63 0           my $reply = $quoter->user_agent->request(GET $url);
64            
65             # Check response
66 0 0         unless ($reply->is_success) {
67 0           $info{ $symbol, "success" } = 0;
68 0           $info{ $symbol, "errmsg" } = join ' ', $reply->code, $reply->message;
69             } else {
70             # Parse the HTML tree
71 0           $tree->parse( $reply->decoded_content );
72            
73             # Find data using xpath
74             # name
75 0           my $name = $tree->findvalue( '//h1[@class="fw--h1 fw--fondsModule-head-content-headline"]');
76 0           $info{ $symbol, 'name' } = $name;
77            
78             # isin
79 0           my $isin_raw = $tree->findvalue( '//span[@class="text_bold"]');
80 0           my @isin = $isin_raw =~ m/^(\w\w\d+)\w./;
81 0           my $sym=$isin[0];
82 0           my $symlen = length($sym);
83 0 0         if($symlen>12) {
84 0           $sym = substr($isin[0], 0, 12);
85             }
86 0           $info{ $symbol, 'isin' } = $sym;
87 0           $info{ $symbol, 'symbol' } = $sym;
88            
89             # date, isodate
90 0           my $raw_date = $tree->findvalue( '//i[@data-key="nav"]/..' );
91 0           my @date = $raw_date =~ m/.(\d\d)\.(\d\d)\.(\d\d\d\d)./;
92 0           $quoter->store_date(\%info, $symbol, {eurodate => "$date[0]/$date[1]/$date[2]"} );
93            
94             # year_range, in this case use table extract
95 0           $te->parse($reply->decoded_content);
96             # the 6th table
97 0           my $details = $te->table(0, 6);
98 0           my $lastRowIndex = @{$details->rows} - 1;
  0            
99             # extract data with re
100 0           my $highest = decimalPeriod($details->cell($lastRowIndex - 1, 1));
101 0           my $lowest = decimalPeriod($details->cell($lastRowIndex, 1));
102 0           $info{ $symbol, "year_range" } = $lowest . ' - ' . $highest;
103            
104             # nav, last, currency
105 0           my $raw_nav_currency = $tree->findvalue( '//div[@class="fw--fondDetail-price"]' );
106 0           my @nav_currency = $raw_nav_currency =~ m/^([0-9,.]+)\s(\w+)/;
107 0           $info{ $symbol, 'nav' } = decimalPeriod($nav_currency[0]);
108 0           $info{ $symbol, 'last' } = $info{ $symbol, 'nav' };
109 0           $info{ $symbol, 'currency' } = $nav_currency[-1];
110            
111             # Other metadata
112 0           $info{ $symbol, 'method' } = 'fondsweb';
113 0           $info{ $symbol, "type" } = "fund";
114 0           $info{ $symbol, "success" } = 1;
115             }
116             }
117              
118 0 0         return wantarray ? %info : \%info;
119             }
120              
121             __END__
122              
123             =head1 NAME
124              
125             Finance::Quote::Fondsweb - Obtain price data from Fondsweb (Germany)
126              
127             =head1 VERSION
128              
129             This documentation describes version 1.00 of Fondsweb.pm, December 28, 2018.
130              
131             =head1 SYNOPSIS
132              
133             use Finance::Quote;
134              
135             $q = Finance::Quote->new;
136              
137             %info = $q->fetch("fondsweb", "LU0804734787");
138              
139             =head1 DESCRIPTION
140              
141             This module obtains information from Fondsweb (Germany),
142             L<https://www.fondsweb.com/>.
143              
144             Information returned by this module is governed by Fondsweb
145             (Germany)'s terms and conditions.
146              
147             =head1 FUND SYMBOLS
148              
149             Use the ISIN number
150              
151             e.g. For L<https://www.fondsweb.com/de/LU0804734787>,
152             one would supply LU0804734787 as the symbol argument on the fetch API call.
153              
154             =head1 LABELS RETURNED
155              
156             The following labels are returned by Finance::Quote::Fondsweb:
157              
158             - currency
159             - date
160             - isin
161             - isodate
162             - last
163             - method
164             - name
165             - nav
166             - type
167              
168              
169             =head1 REQUIREMENTS
170              
171             Perl 5.012
172             HTML::TableExtract
173             HTML::TreeBuilder::XPath
174              
175             =head1 ACKNOWLEDGEMENTS
176              
177             Inspired by other modules already present with Finance::Quote
178              
179             =head1 AUTHOR
180              
181             Diego Marcolungo
182              
183             =head1 LICENSE AND COPYRIGHT
184              
185             Copyright (C) 2018, Diego Marcolungo.
186              
187             This program is free software: you can redistribute it and/or modify
188             it under the terms of the GNU General Public License as published by
189             the Free Software Foundation, either version 3 of the License, or
190             (at your option) any later version.
191              
192             =head1 DISCLAIMER
193              
194             This program is distributed in the hope that it will be useful,
195             but WITHOUT ANY WARRANTY; without even the implied warranty of
196             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
197             GNU General Public License for more details.
198              
199             =head1 SEE ALSO
200              
201             Fondsweb (Germany), L<https://www.fondsweb.com/>
202              
203             =cut