File Coverage

blib/lib/Finance/NASDAQ/Quote.pm
Criterion Covered Total %
statement 14 56 25.0
branch 0 22 0.0
condition 0 2 0.0
subroutine 5 9 55.5
pod 1 1 100.0
total 20 90 22.2


line stmt bran cond sub pod time code
1             package Finance::NASDAQ::Quote;
2              
3 2     2   54465 use warnings;
  2         5  
  2         65  
4 2     2   11 use strict;
  2         5  
  2         83  
5              
6 2     2   2464 use HTML::TreeBuilder;
  2         92841  
  2         25  
7 2     2   2135 use LWP::Simple qw($ua get);
  2         184000  
  2         22  
8             $ua->timeout(15);
9              
10             require Exporter;
11             our @ISA = qw(Exporter);
12             our @EXPORT_OK = qw/getquote/;
13              
14             =head1 NAME
15              
16             Finance::NASDAQ::Quote - Fetch real time stock quotes from nasdaq.com
17              
18             =head1 VERSION
19              
20             Version 0.07
21              
22             =cut
23              
24             our $VERSION = '0.07';
25              
26              
27             =head1 SYNOPSIS
28              
29             Fetch real time stock quotes from nasdaq.com
30              
31             use Finance::NASDAQ::Quote qw/getquote/;
32              
33             my %quote = getquote('F');
34             my $text = getquote('V');
35              
36             =head1 EXPORT
37              
38             None by default.
39              
40             =head1 FUNCTIONS
41              
42             =head2 getquote( SYMBOL )
43              
44             In list context, returns a hash containing the price, net change,
45             percent change, sign ('+' or '-'), and volume for stock SYMBOL, or
46             an empty list on error.
47              
48             In scalar context, returns a formatted string suitable for human
49             consumption, or undef on error.
50              
51             =cut
52              
53             sub getquote {
54 0     0 1 0 my ($symbol,$ua) = @_;
55 0         0 my $url = "http://www.nasdaq.com/aspx/nasdaqlastsale.aspx?symbol=$symbol&selected=$symbol";
56 0         0 my @ids = qw/_LastSale _NetChange _PctChange _Volume/;
57 0         0 my $content;
58 0 0       0 if (defined $ua) {
59 0         0 my $resp = $ua->get($url);
60 0 0       0 $content = $resp->content() if $resp->is_success();
61             } else {
62 0         0 $content = get $url;
63             }
64 0 0 0     0 warn "NASDAQ is down" and return unless defined $content;
65              
66 0         0 my $tree = HTML::TreeBuilder->new;
67 0         0 $tree->parse($content);
68              
69 0         0 my %quote;
70 0         0 @quote{qw/prc net pct vol/} = map { _findspan($tree, $_) } @ids;
  0         0  
71              
72 0         0 my $img = $tree->look_down('_tag', 'img', _id('_updownImage'));
73 0 0       0 if ($img) {
74 0         0 my ($color) = ($img->attr('src') =~ /(\w+)ArrowSmall/);
75 0 0       0 $quote{sgn} = $color eq 'green' ? '+' : '-';
76             } else {
77 0         0 warn "Failed to locate updownimage";
78 0         0 $quote{sgn} = undef;
79             }
80 0 0       0 if ($quote{net} eq 'unch') { $quote{net} = 0 };
  0         0  
81              
82 0         0 ($quote{nam}) = ($tree->find('title')->as_text() =~ /^([^(]+) \(\S+\)/);
83 0 0       0 if (defined $quote{nam}) {
84 0         0 $quote{nam} =~ s/ +$//g;
85             } else {
86 0         0 warn "Could not parse title";
87             }
88              
89 0         0 $tree = $tree->delete();
90              
91 0 0       0 return if grep {not defined} values %quote;
  0         0  
92 0 0       0 return wantarray ? %quote : _as_text($symbol, %quote);
93             }
94              
95             # for look_down
96             sub _id {
97 0     0   0 my $id = shift;
98             return sub {
99 0     0   0 my ($tag) = @_;
100 0 0       0 if (defined $tag->attr('id')) {
101 0         0 return $tag->attr('id') eq $id;
102             } else {
103 0         0 return 0;
104             }
105             }
106 0         0 }
107              
108             sub _findspan {
109 0     0   0 my ($tree,$id) = @_;
110 0         0 my $elem = $tree->look_down('_tag', 'span', _id($id));
111 0 0       0 if (defined $elem) {
112 0         0 return $elem->as_text;
113             } else {
114 0         0 warn "Could not find span $id";
115 0         0 return undef;
116             }
117             }
118              
119             # format %quote as a string
120             sub _as_text {
121 1     1   735 my ($symbol,%quote) = @_;
122 1         28 return sprintf ("%s (%s): \$%g, %s%s (%s%s), vol %s", $quote{nam},
123             $symbol, @quote{qw/prc sgn net sgn pct vol/});
124             }
125              
126             =head1 AUTHOR
127              
128             Ian Kilgore, C<< >>
129              
130             =head1 BUGS/TODO
131              
132             nasdaq.com (and hence getquote) returns curiously formatted strings,
133             rather than numbers. getquote should 'numify' these.
134              
135             It is likely that nasdaq.com will be changing their site some time
136             in 2009. Watch for updates.
137              
138             The module lacks many tests. getquote could be made more modular so
139             as to avoid requiring an internet connection to test it.
140              
141             Please report any bugs or feature requests to C, or through
142             the web interface at L. I will be notified, and then you'll
143             automatically be notified of progress on your bug as I make changes.
144              
145              
146             =head1 SUPPORT
147              
148             You can find documentation for this module with the perldoc command.
149              
150             perldoc Finance::NASDAQ::Quote
151              
152              
153             You can also look for information at:
154              
155             =over 4
156              
157             =item * RT: CPAN's request tracker
158              
159             L
160              
161             =item * AnnoCPAN: Annotated CPAN documentation
162              
163             L
164              
165             =item * CPAN Ratings
166              
167             L
168              
169             =item * Search CPAN
170              
171             L
172              
173             =back
174              
175             =head1 COPYRIGHT & LICENSE
176              
177             Copyright 2008 Ian Kilgore, all rights reserved.
178              
179             This program is free software; you can redistribute it and/or modify it
180             under the same terms as Perl itself.
181              
182              
183             =cut
184              
185             1;