Banking

Using Perl's Finance::Quote to retrieve stock information from the Web

Perl's CPAN contains many gems, and one of them is undoubtedly the Finance::Quote module. Designed to ease the task of retrieving stock prices off the Internet, the module makes it simple for developers to integrate stock-tracking mechanisms into their applications. We'll show you how.

Perl's CPAN contains many gems, and one of them is undoubtedly the Finance::Quote module. Designed to ease the task of retrieving stock prices off the Internet, the module makes it simple for developers to integrate stock-tracking mechanisms into their applications and thus create customized reports on financial market movements over differing time periods or investment portfolios.

If you're a Perl developer looking to build a Web-based stock ticker or portfolio tracker for equity markets and/or mutual funds, keep reading, because this article will teach you how to:

● Retrieve stock prices and market data for stocks traded on the major exchanges, such as the NYSE and NASDAQ.

● Retrieve mutual fund NAVs from a variety of online sources.

● Create a simple MySQL-based portfolio tracker to display the current value of an investment basket.

Installation

The Finance::Quote package was originally part of the GnuCash application until it was broken out as a separate project. The package consists of a base module that provides the underlying query methods and a series of supplementary modules that take care of parsing third-party Web sites for the required data. A variety of data sources are supported, and developers can easily add new sources as needed.

The package is licensed under the GPL and is currently maintained by Paul Fenwick. You can download it from the SourceForge site or from the CPAN page. The download archive provides detailed installation instructions, but by far the simplest way to install it is to use the CPAN shell:

shell> perl -MCPAN -e shell
cpan> install Finance::Quote

Finance::Quote depends on three other packages: LWP::UserAgent, HTTP::Request::Common, and HTML::TableExtractor. If yours is a relatively recent Perl installation, you'll probably already have the first two; you can download the third from this site. If you use the CPAN shell, dependencies will be automatically downloaded for you (unless you've configured your CPAN shell to ignore dependencies, in which case you'll need to download and install these three packages manually).

One important note before you proceed: The data retrieved by the Finance::Quote module is governed by the terms and conditions of the source from whence it was retrieved. So before you go out there and start selling your code to the highest bidder, take a close look at the license terms and data usage restrictions to ensure that you're in compliance. The examples here are purely illustrative. Okay, so let's start retrieving stock data.

Retrieving stock prices with Finance::Quote


Here's a simple example of using the Perl Finance::Quote package to retrieve the price of a fictitious stock (symbol XYZ) from the NYSE:

#!/usr/bin/perl

# import module
use Finance::Quote;

# create object
my $q = Finance::Quote->new();

# retrieve stock quote
my %data = $q->fetch('nyse', 'XYZ');

# print price
print "The current price of XYZ on the NYSE is " . $data{'XYZ', 'price'};

Since Finance::Quote provides an object-oriented interface, the first step is to create an object with new(). This object exposes a number of methods, including the fetch() method. This method accepts two arguments: the name of the data source and the stock symbol.

The data returned by fetch() is structured as a two-dimensional hash: The first dimension is the stock symbol, and the second is a label corresponding to the attribute received. The hash returned by fetch() includes a number of different labels, some of which are listed below (a complete list is available in the online documentation):

name—official name
price—last trade
high—highest price today
low—lowest price today
volume—number of shares traded today
year_range—52-week price range
pe—current P/E ratio
nav—net asset value for mutual fund
exchange—the source exchange
success—Boolean indicating if data retrieval was successful
errormsg—error string if data retrieval was unsuccessful

So, to retrieve a particular data fragment from the two-dimensional hash, you'd use the following notation:

$hash(symbol, label)

This is clearly shown in the last line of the example above, which uses this notation to retrieve the price of XYZ stock.

Tip: You can have fetch() retrieve more than one quote at a time by specifying a comma-separated list (or an array) of stock symbols as the second input argument.

Okay, so that's stock prices. Now let's look at how to retrieve the NAV for a mutual fund.

Retrieving mutual fund NAV with Finance::Quote


The net asset value, or NAV, of a mutual fund is its assets minus its liabilities—in essence, the net worth of the mutual fund. To retrieve a mutual fund's NAV using the Perl Finance::Quote package, simply use the fetch() method with an appropriate data source and the mutual fund symbol:

#!/usr/bin/perl

# import module
use Finance::Quote;

# create object
my $q = Finance::Quote->new();

# set mutual fund code
# each fund has a unique code
my $fcode = '1#761';

# retrieve mutual fund NAV
my %quotes = $q->fetch('indiamutual', $fcode);

# print details
if ($quotes{$fcode, 'success'})
{
      print "NAV of " . $quotes{$fcode, 'name'} . " is " . $quotes{$fcode, 'nav'}; } else
{
      die "Data retrieval error";
}

If Finance::Quote is unable to retrieve the data successfully, it sets the success key of the return hash to 0 (false) and places an error message in the errormsg key. By checking for this, you can implement basic error-handling routines into your Perl script, as I've done above.

Note that in many countries (for example, Canada and India), mutual funds do not have a unique global symbol. In such cases, you'll need to manually locate the mutual fund code assigned by the country's fund watchdog and use that in your Perl script. Links and instructions on how to accomplish this are included in the specific Finance::Quote submodule's documentation.

Now let's take a look at how your Perl program can retrieve the available data sources.

Retrieving available data sources with Finance::Quote


Since the Perl Finance::Quote package uses data from a variety of sources, a natural question (especially if you're letting the user choose the exchange or region) is: How do you find out which data sources are supported? The answer: with the sources() method.

#!/usr/bin/perl

# import module
use Finance::Quote;

# create object
my $q = Finance::Quote->new();

# retrieve sources
my @sources = $q->sources();

# print sources
print "Available sources are: ";
foreach $s (@sources)
{
      print "$s  ", ;
}

Here's an example of the output:

Available sources are: vwd  nyse  fidelity_direct  canadamutual  asxaustralia  usa  troweprice  amfiindia  tdwaterhouse  fool  nasdaqbmonesbittburns  trustnet  ftportfolios_direct  yahoo_asia  dutchuk_unit_trusts  canada  troweprice_direct  tiaacref  yahoo  ftportfolios fidelity  fundlibrary  aex  dwsfunds  yahoo_australia  yahoo_europe vanguard  indiamutual  asia  europe

Some of the more important sources in this list are Yahoo! Finance (in all major world regions), the NYSE and NASDAQ, the Australian Stock Exchange, and data from Canadian, European, and Asian markets. In some cases, most notably Asia, you need to suffix the stock symbol with an exchange identifier as well.

You might notice an overlap among the various source names. This is because some are specific to exchanges, while others are more general country databases. For example, use "usa" for U.S. market data, but "nyse" or "nasdaq" to limit the query to the respective exchanges only.

Now let's look at a more detailed example: a simple portfolio tracker.

A simple portfolio tracker with Finance::Quote and MySQL


With a little imagination, you can use the Perl Finance::Quote package for some very interesting financial applications. The one I like the most is an online portfolio tracker, which gives you real-time data on whether your investments are making money or not. Such an application would store information on your past stock purchases—quantity and purchase price—and retrieve, on demand or at regular intervals, the latest prices off the Web for quick comparison and evaluation.

To develop this application, I'll assume the existence of a MySQL table containing stock symbols, the quantities purchased of each, and the purchase prices of each. It looks something like this:

+——+————+———+————+
| id | symbol | qty  | pprice |
+——+————+———+————+
|  1 | MSFT   |  500 |     17 |
|  2 | YHOO   | 3200 |  45.65 |
|  3 | WMT    |  100 |  53.29 |
|  4 | GE     | 1500 |  12.57 |
+——+————+———+————+

This example table holds portfolio information for a single user. Adding multiuser capability is as easy as adding a new owner field to each record and filtering by owner in the SQL query.

The next task is to develop a CGI script to communicate with MySQL, retrieve the portfolio data, and combine it with the latest prices from the Web. The original and current prices can then be compared to offer some insight into whether your portfolio is appreciating or depreciating, in both absolute and percentage terms (see Listing A).

After sending the standard HTML headers, the script in Listing A uses the Perl DBI to open a connection to the MySQL database and query it for the list of stocks, quantities, and original prices. Then, as it iterates over the record result returned by the query, the Finance::Quote module is used to retrieve the latest price of each stock. The two prices are then compared, and the change in absolute and percentage terms is recorded. Once all the records have been retrieved, the information generated is displayed in a neat table, together with summary totals.

Of course, this is just one of the myriad applications of Finance::Quote. With power like this at your fingertips, there's literally a whole world at your disposal. So go on...give your creativity full rein!

Editor's Picks

Free Newsletters, In your Inbox