I've spend some time searching around for a Finance module that could retrieve major futures price board quotes. After many failed attempts, I decided to roll my own. Now, I'd like to submit it to CPAN. However, before the submission, I'd would also like to put the module through the monastery. Please feel free to comment (and suggest fixes). Thanks.
package Finance::FuturesQuote; use vars qw/$VERSION %categories/; $VERSION = 0.01; =head1 NAME Finance::FuturesQuote - Get major futures price board quotes from INO. +com =head1 SYNOPSIS use strict; use Finance::FuturesQuote; my %quotes = Finance::FuturesQuote::GetFuturesQuotes(qw[CL BO] +); my %quotes = Finance::FuturesQuote::GetAllFuturesQuotes(); =head1 DESCRIPTION This module gets quotes from INO.com for all major futures price board +. The B<GetFuturesQuotes> function will return quotes for the specified +symbols, while the B<GetAllFuturesQuotes> function will return a quote for each + of the known symbols. The download operation is efficient: only one request is made even if several symbols are requested at once. =cut use strict; use Carp; use warnings; use LWP::UserAgent; use HTTP::Request; use HTML::TableContentParser; # use Data::Dumper; =head2 AVAILABLE SYMBOLS Finance::FuturesQuote can only access quotes for futures in the follow +ing price board categories Energy Metals Food and Fiber Grains and Oilseeds Interest Rates Livestock and Meats Each category is an entry in a global hash, with the value being a has +h of all available symbols and their respective names. To see a complete li +sting of all known symbols and names from the program, foreach my $category (keys %Finance::FuturesQuote::categories) { print "$category =>\n"; foreach (keys %{$Finance::FuturesQuote::categories{$category}} +) { print " $_ => $Finance::FuturesQuote::categories{$categ +ory}{$_}\n"; } } =cut our %categories = ( 'Energy' => { 'HU' => 'New York Harbor Unleaded Gasoline', 'HO' => 'Heating Oil', 'NG' => 'Henry Hub Natural Gas', 'CL' => 'Light Sweet Crude Oil', 'PN' => 'Propane' }, 'Metals' => { 'GC' => 'Gold', 'AF' => 'Aluminum', 'YG' => 'Mini NY Gold', 'YI' => 'Mini NY Silver', 'PA' => 'Palladium', 'SI' => 'Silver', 'PL' => 'Platinum', 'HG' => 'Copper' }, 'Food and Fiber' => { 'OJ' => 'Orange Juice Froz. Conc.', 'DA' => 'BFP Milk', 'SB' => 'Sugar', 'DB' => 'Butter', 'KC' => 'Coffee', 'LB' => 'Random Length Lumber', 'SE' => 'Sugar', 'CT' => 'Cotton', 'CC' => 'Cocoa', 'NF' => 'Nonfat Dry Milk', 'OD' => 'Orange Juice Froz. Conc. Diff.', }, 'Grains and Oilseeds' => { 'VW' => 'Wheat', 'WU' => 'Wheat', 'ZO' => 'Oats', 'ZM' => 'Soybean Meal', 'SX' => 'Soybeans', 'VZ' => 'Corn', 'BO' => 'Soybean Oil', 'SM' => 'Soybean Meal', 'YW' => 'Mini Wheat', 'YK' => 'Mini Soybeans', 'RR' => 'Rough Rice', 'YC' => 'Mini Corn', 'VL' => 'Soybean Oil', 'VQ' => 'Rough Rice', 'CU' => 'Corn', 'OZ' => 'Oats', 'VS' => 'Soybeans', }, 'Interest Rates' => { 'ZB' => 'U.S. Treasury Bond', 'TY' => 'Treasury Notes 10yr', 'US' => 'U.S. Treasury Bond', 'TU' => 'Treasury Notes 2yr', 'EM' => 'Libor 1month', 'EL' => 'Euroyen', 'ZQ' => 'Fed Funds 30d', 'ZN' => 'Treasury Notes 10yr', 'FF' => 'Federal Funds 30day', 'TE' => '28-Day Mexican TIIE', 'ZT' => 'Treasury Notes 2yr', 'ZF' => 'Treasury Notes 5yr', 'EY' => 'Euroyen (TIBOR)', 'FV' => 'Treasury Notes 5yr', 'ED' => 'Eurodollar', 'AN' => 'Agency Notes 10yr', }, 'Livestock and Meats' => { 'LH' => 'Lean Hogs', 'LC' => 'Live Cattle', 'PB' => 'Frozen Pork Bellies', 'FC' => 'Feeder Cattle', } ); ##### Public Functions ##### =head2 METHODS =over 4 =item GetFuturesQuotes(list) This function takes a list of symbols as the only arguement. The user +can pass in as few or as many symbols as desired. The module will make a single + access of the data to improve efficiency. If the list starts getting too long +, it might just be easier to use the second method instead. The return format is +outlined below. =cut sub GetAllFuturesQuotes { my @symbols; foreach my $group (keys %categories) { foreach (keys %{$categories{$group}}) { push @symbols,$_; } } return GetFuturesQuotes(@symbols); } =item GetAllFuturesQuotes() This function will get the quotes for all known symbols. The return fo +rmat is outlined below. =back 4 =cut sub GetFuturesQuotes { my %quotes; my $rawdata = _retrieveQuotes(); foreach (@_) { _findQuote(\$rawdata, $_, \%quotes); } return %quotes; } ##### Internal Functions ##### sub _retrieveQuotes { my $ua = LWP::UserAgent->new; + # Create a new UserAgent $ua->agent('Mozilla/25.'.(localtime)." (PERL ".__PACKAGE__." $VERSIO +N"); # Give it a type name my $url = 'http://quotes.ino.com/exchanges/futboard/'; my $req = new HTTP::Request('GET',$url) or die "Could not GET.\n" an +d return undef; my $res = $ua->request($req); + # $res is the object UA returned if (not $res->is_success()) { + # If successful warn "Failed to GET.\n"; return undef; } return $res->content; } sub _findQuote { my $dataref = shift; my $symbol = shift; my $href = shift; my $p = HTML::TableContentParser->new(); my $table = $p->parse($$dataref); my ($tblnum,$rownum) = _getGroupDataStart($table, _getGroupName($sym +bol)); die "Cannot find group heading for $symbol." unless defined $tblnum +and defined $rownum; for $rownum ($rownum+2 .. scalar(@{$$table[$tblnum]{rows}})-1) { if ($$table[$tblnum]{rows}[$rownum]{cells}[0]{data} =~ />$symbol/) + { # print "Found $symbol\n" . Dumper($$table[$tblnum]{rows}[$rownu +m]{cells}); $$href{$symbol}{Last} = $$table[$tblnum]{rows}[$rownum]{cells} +[1]{data}; $$href{$symbol}{Change} = $$table[$tblnum]{rows}[$rownum]{cells} +[2]{data}; $$href{$symbol}{Volume} = $$table[$tblnum]{rows}[$rownum]{cells} +[3]{data}; $$href{$symbol}{OI} = $$table[$tblnum]{rows}[$rownum]{cells} +[4]{data}; $$href{$symbol}{Time} = $$table[$tblnum]{rows}[$rownum]{cells} +[5]{data}; $$href{$symbol}{Change} =~ />(.*?)</; $$href{$symbol}{Change} = $1; return; } } } sub _getGroupName { my $n = shift; foreach my $group (keys %categories) { foreach (keys %{$categories{$group}}) { return $group if ($ _ eq $n); } } return undef; } sub _getGroupDataStart { my $table = shift; my $group = shift; die "Undefined group heading." unless defined $group; # find the start of the table data for this symbol's group for my $tblnum (0 .. scalar(@{$table})-1) { for my $rownum (0 .. scalar(@{$$table[$tblnum]{rows}})-1) { next unless exists $$table[$tblnum]{rows}[$rownum]{cells}[0]{dat +a}; if ($$table[$tblnum]{rows}[$rownum]{cells}[0]{data} =~ /<a name= +"$group"/i) { # print "Found start of $groupname at $tblnum,$rownum\n" . D +umper($$table[$tblnum]{rows}[$rownum]); return ($tblnum,$rownum); } } } return (undef,undef); } =head2 RETURN FORMAT The return value of either function is an hash of hashes, with the fol +lowing style structure: $VAR1 = { 'CL' => { 'Change' => '0.00', 'Last' => '60.73', 'Time' => 'set 14:46', 'Volume' => '1643', 'OI' => '200914' }, 'SX' => { 'Change' => '0', 'Last' => '707 1/2', 'Time' => 'set 14:24', 'Volume' => '52238', 'OI' => '185920' } }; where the keys of the hash are the requested symbols and each value is + a hash of all information available from http://quotes.ino.com/exchanges/fut +board/ =head1 PROBLEMS? If this doesn't work, INO has probably changed their HTML format. Let me know and I'll fix the code. Or by all means send a patch. =head1 SEE ALSO L<LWP::UserAgent>, L<HTTP::Request>, L<HTML::TableContentParser>. =head1 AUTHOR Paul Grinberg, gri6507 -at- yahoo -dot- com. =cut 1;
Edit g0n - Changed title from "New CPAN module"
In reply to RFC: Finance::FuturesQuote by gri6507
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |