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 function will return quotes for the specified symbols, while the B 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 following 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 hash of all available symbols and their respective names. To see a complete listing 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{$category}{$_}\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 format 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__." $VERSION"); # 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" and 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($symbol)); 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}[$rownum]{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} =~ />(.*?) { '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/futboard/ =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, L, L. =head1 AUTHOR Paul Grinberg, gri6507 -at- yahoo -dot- com. =cut 1;