PREVIOUS  TABLE OF CONTENTS  NEXT 

Finance::Quote

Paul Fenwick

  Resources:  
Finance::Quote ...................................................... CPAN
Finance::YahooQuote ............................................ CPAN
Gnucash ....................................... http://www.gnucash.org
LWP::UserAgent ................................................... CPAN

If you have a reason to watch the world's financial markets, and you know a little Perl, you may find the Finance::Quote module handy. I personally use it to remind myself that I should never buy stocks, as I have a good history of losing money in the market. However, you can use Finance::Quote to help track those tasty stock options you've been offered, or even to help you build dynamic artwork driven by fluctuations in the world markets. (Yes, thisactually exists and uses Finance::Quote under the hood: http://www.terrestrialmap.org/StockPuppets.htm.

Finance::Quote is a Perl module that makes accessing financial information easy. You can look up stocks and shares, managed funds, currency rates, and all for a variety of countries and markets. It's even easy to add your own specialized sources if you find something not covered by the module.

History

Finance::Quote started as the Quote module which was distributed as part of Gnucash (http://www.gnucash.org). This module (simply called "Quote") was a modified version of Finance::YahooQuote written by DJ Padzensky (http://www.padz.net/~djpadz/YahooQuote/). Linas Vepstas and Yannick Le Ny added extra sources for GnuCash, at which point I asked if anyone had any objections to me breaking it off into a separate project with a range of uses outside of GnuCash.

Since that time, many people have contributed to Finance::Quote, including Xose Manoel Ramos (for inheritable Yahoo! methods), Brent Neal, Keith Refson, and Volker Stuerzl for writing pluggable modules, and Peter Thatcher, Jacinta Richardson, and Steven Murdoch for various bugfixes and improvements. Ben Hemming was kind enough to save the world from my poor web design skills and supply a web page look and feel.

Legality

When discussing Finance::Quote, one question which often arises is "How legal is all this?" Finance::Quote obtains quotes from various organizations who make this information available via the web. Fetching the data is legal; web browsers do it all the time, and Finance::Quote is just a rather specialized web browser. (Although there have been a couple of court cases where "deep linking" into web pages has been cast into legal shadow.) The main problems occur with the use of that data.

Each organization has a different set of restrictions and conditions pertaining to the data you obtain from them. The most common restriction is forbidding redistribution, although some of them are so odd as to limit the number of copies you can have in memory at any one time! The Finance::Quote manual pages provide some pointers as to where these licenses can be found, and it would be wise to check those licenses to stay in safe legal waters.

In general, obtaining information and displaying it or processing it into some useful form for personal use should be okay. After all, that's what your web browser does. Obtaining the information and re-branding it as your own is probably a no-no. If in doubt, check with a lawyer.

Terminology

Before we begin, it's worth taking the time to explain a few pieces of terminology that might confuse. For simplicity, a stock, mutual fund, index, or other parcel of information which can be fetched using Finance::Quote we will refer to as a "stock".

All stocks have a unique symbol, an identifier which we can use to look them up; and an exchange, a locality in which they exist. For example, VA Linux has the symbol "LNUX" on the NASDAQ stock exchange. Symbols are traditionally all upper-case, but there exist some symbols (such as the pseudo-symbols used in the TIAA-CREF module, Finance::Quote::Tiaacref) that are mixed case.

Finance::Quote essentially provides a way of taking a list of symbols for a given exchange, and returning information about those symbols. Each bit of information has a "label" (such as volume, close, high, low, and so on), identifying what that information is. All making sense? Good. Let's do something fun then.

Using Finance::Quote: The Basics

I'll demonstrate the usage of Finance::Quote by way of a useful example, which will be expanded upon as we go. For starters, let's just say you're interested in stocks from a single market, and wish to print their current value and volume traded.

#!/usr/bin/perl -w
use strict;
use Finance::Quote;


my $exchange = shift;	# Where we fetch our stocks from.
my @symbols = @ARGV;    # Which stocks we want.

my $quoter = Finance::Quote->new;      # Create the F::Q object.

$quoter->timeout(30);	# Cancel fetch operation if it
				        # takes longer than 30 seconds.

# Grab our information and place it into %info.
my %info = $quoter->fetch($exchange, @symbols);

foreach my $stock (@symbols) {
	unless ($info{$stock, "success"}) {
		warn "Lookup of $stock failed - ".$info{$stock, "errormsg"}.
		     "\n";
		next;
	}
	print "$stock:\t\t",
	      "Volume: ", $info{$stock, "volume"}, "\t",
	      "Price: " , $info{$stock, "price"}, "\n";
}

If our script was called showstocks, and you were interested in Australian supermarkets, you could call it like this:

  showstocks australia CML WOW

This provides you with information about Coles-Myer and Woolworths.

Alternatively, if you were interested some U.S. technology stocks, you could try this:

  showstocks usa LNUX RHAT MSFT IBM

which provides you with information about VA Linux, Red Hat, Microsoft, and International Business Machines.

This script demonstrates a number of capabilities of Finance::Quote. In particular:

• Finance::Quote is object-oriented, and a Finance::Quote object can be generated using Finance::Quote->new().

• The fetch() method can be used for retrieving information. This method is very powerful, and will be explained in depth later in this article.

• The fetch() method returns a two-dimensional hash. This is the topic of our next section.

The Return Hash

Finance::Quote's most useful function, fetch(), returns a two-dimensional hash. This contains a variety of information about the stocks you requested, including volume, price, highs and lows, percentage changes, and other information. Each key in the hash has two parts:

  $info{$symbol,$label}

$symbol is the symbol that you've requested. In the examples above, RHAT and LNUX are examples of symbols. The label refers to a specific type of information about that stock, such as volume, price, close, p_change, or name. Labels are always lowercase.

There exist some very special labels you should be aware of. The label success is used to indicate if the information could be successfully retrieved. If the value of the success label for a given stock is false, then no useful information could be gained about that symbol at this time. If a failure did occur, the reason for that failure will be in the label errormsg.

The special label price is used to indicate the value of the given stock. This varies a little depending on what information you're fetching. For stocks, it's usually the last price the stock was traded at. For some investments, it's the current yield (a percentage per-annum). For currencies it's the exchange rate, and for indexes it's the last value of that index (in points).

Standard Finance::Quote Labels

The reason the price label is important is that it allows for applications to track movements without having to know what it is we're tracking: a stock, a managed fund, or an indicator. The price label provides us with the information we want. This is particularly useful for stock ticker programs, allowing them to use Finance::Quote to track things other than just stocks.

For applications that care about the details, there are a wide range of labels that can be returned. These include the highest and lowest prices for the day, dividend yields and dates, the time and date that the information is current for, the volume traded, the name of the stock, and many others. The standard labels are listed in the sidebar.

It's important to remember that the information fetched by Finance::Quote is usually delayed, and so is often 30 minutes or more behind what's really happening. If you're doing currency conversions as well, then the currency conversion rate may also be delayed. You can use the labels date and time to determine when the data was registered — it's not unknown for some sources to provide data that is a week old or more.

Advanced Usage

The basics of Finance::Quote are pretty simple. You create yourself a Finance::Quote object, ask it for some information, and you get that information back in a hash. For most applications, this is all you really need. However, Finance::Quote provides a wide range of extra features to help make your life easier.

Currency Conversion

Finance::Quote has the ability to look up currency rates, and can even automatically convert foreign stocks into local currencies. Let's say you live in Australia, but own some American stocks. You may be interested in knowing the value of those stocks in Australian dollars, which have more meaning to you than US dollars. Here's how:

#!/usr/bin/perl -w
use strict;
use Finance::Quote;

my $market = shift;
my @stocks = @ARGV;
my $quoter = Finance::Quote->new();
$quoter->set_currency("AUD"); # Aussie dollars.
my %info = $quoter->fetch($market,@stocks);
# Print the info here.

The set_currency() method asks Finance::Quote to convert all values into the given currency before returning them to you. Finance::Quote knows which things it can convert (like prices and ranges), and which it cannot (like percentage changes and volumes). It's even smart enough to (usually) not touch indexes and other abstract indicators that don't have currencies attached to them.

Be aware that set_currency() can significantly increase the time of a query, as currency lookup information has to be fetched as well as the stock information.

It's also possible to fetch currency exchange rates directly. This is done using the currency() method. For example:

  my $exchange_rate = $quoter->currency("USD","AUD");
  print "1 US dollar is $exchange_rate Australian dollars.\n";

The currency() method can also do clever things like take a prefix for the currency being converted from. The following script is a quick and dirty command-line utility to convert between currencies:

#!/usr/bin/perl -w
use strict;
use Finance::Quote;

# Command-line currency conversion.

die "Usage: $0 FROM TO\n" unless defined($ARGV[1]);

my $quoter = Finance::Quote->new();
my $exchange_rate = $quoter->currency($ARGV[0],$ARGV[1]);

die "Don't know how to convert $ARGV[0] to $ARGV[1]\n" unless $exchange_rate;

print "$ARGV[0] -> $ARGV[1] = $exchange_rate\n";

If this script were to be called currency-lookup, you could show the going rate between Australian and American dollars like this:

  currency-lookup AUD USD

If you wanted to know how much 95 Australian dollars were in French francs, you could do this:

  currency-lookup "95 AUD" FRF

Fail-over Support and Custom Modules

Finance::Quote provides automatic fail-over support if you specify the market that you're interested in and not the actual source from which you want to fetch it. This means that if you use nasdaq instead of yahoo as your source, Finance::Quote will automatically try all sources of NASDAQ data in case the first one failed. Fail-over support is turned on by default in all Finance::Quote objects.

Fail-over support can increase the time of a query, especially if you're searching for a non-existent stock. It's possible to (un)set fail-over support explicitly like this:

  $quoter->failover(0);   # Disable failover.

Likewise, when you create your Finance::Quote object, it's possible to state which modules you'd like to be able to fetch information from. For example, this uses only the Finance::Quote::Yahoo::Australia module for queries:

  my $quoter = 
		Finance::Quote->new("Yahoo::Australia");

This style of invocation is useful if you prefer a particular information supplier, or otherwise wish to restrict where Finance::Quote can search for information.

Also, specifying modules to load at creation time lets you load custom modules that are not part of the standard Finance::Quote distribution.

  my $quoter = 
		Finance::Quote->new("-defaults", "MyBank");

Here we would load the Finance::Quote:: MyBank module, as well as all the default modules packaged with Finance::Quote. Note that the -defaults argument is only magical when passed as the first argument (although in the future it might be legal to pass it anywhere in the arguments list).

If you're interested in writing your own modules for Finance::Quote, you should read the Hacker's Guide that comes with Finance::Quote, or which can be found in the Finance::Quote documentation manager at http://sourceforge.net/docman/index.php?group_id=4232.

Required Labels

Fail-over support is a wonderful thing — the source you're fetching data from can disappear and you'll never have to know. Unfortunately, not all sources provide all the information you're looking for, and having bits of information disappear when you're used to them can be a little surprising.

Rather than having to worry about your fail-over sources not providing the information you're looking for, Finance::Quote allows you to define a list of things that are important to you, using the require_labels() method. Say that your program relies upon the price, date, high, low, and volume labels. You can express this to your Finance::Quote object like so:

    $quoter->require_labels(qw/price date high low volume/);

If you now use the $quoter->fetch() to obtain information, you can be guaranteed that those fields will be available when they make sense for whatever you've requested. This means you can use fail-over methods safe in the knowledge that the information you actually care about won't disappear.

Listing 1: A sample stock ticer program using Finance::Quote.

Tricks With The User Agent

If you've ever used LWP::UserAgent before, then you'll be pleased to know that you can customize the underlying LWP::UserAgent object in Finance::Quote. For example, this causes the $quoter object to identify itself as MyTicker/0.1 in HTTP sessions.

  $quoter->user_agent->agent("MyTicker/0.1");

Likewise, this lets you set your proxy explicitly:

  $quoter->user_agent->proxy('http', $MY_PROXY);

Note that the UserAgent respects proxy environment variables (such as http_proxy) at creation time. For more information on what you can and cannot do here, check out the documentation for LWP::UserAgent.

Rolling Your Own Finance::Quote Module

As well as using the standard Finance::Quote modules, it's also possible to write your own module for Finance::Quote to use. Writing such a module can be a tricky task, and is beyond the scope of this article.

The Finance::Quote package does come with its own Hacker's Guide explaining how to write a Finance::Quote module. This can be found with other documentation at http://finance-quote.sourceforge.net/documentation.html.

An Example Stock Ticker Program

On the previous page is an example of a useful, real, text-based stock ticker. The code is intentionally simple to display the features of Finance::Quote, but it provides a very clear and useful display for stocks that you may have your eye on.

_ _END_ _


Paul Fenwick (pjf@cpan.org) lives in Melbourne (Australia) and has interests in permaculture, edible plants, and rides a push-bike named "Biscuit". He currently hacks Perl for a living. Paul records his exciting adventures at http://www.advogato.net/person/pjf/.
PREVIOUS  TABLE OF CONTENTS  NEXT