Finance-Quote-Grab
view release on metacpan or search on metacpan
lib/Finance/Quote/MGEX.pm view on Meta::CPAN
contract_month_iso time
) ]);
}
# These are about 30 kbytes and 25 kbytes, and update every 60 seconds
# apparently, but there's no ETag or Last-Modified to save re-downloading.
#
use constant MGEX_AQUOTES_URL =>
'http://sites.barchart.com/pl/mgex/aquotes.htx';
use constant MGEX_WQUOTES_URL =>
'http://sites.barchart.com/pl/mgex/wquotes_js.js';
my %aq_url = (a => MGEX_AQUOTES_URL,
w => MGEX_WQUOTES_URL);
# For individual quotes, but the pages are bigger than the wquote/aquote
# # eg. http://www.mgex.com/quotes.html?page=quote&sym=MW
# use constant MGEX_QUOTES_BASE =>
# 'http://www.mgex.com/quotes.html?page=quote&sym=';
sub mgex_quotes {
my ($fq, @symbol_list) = @_;
### mgex_quotes() ...
### @symbol_list
my $ua = $fq->user_agent;
my %quotes;
# while (@symbol_list) {
# my $symbol = shift @symbol_list;
# my $commodity = symbol_to_commodity($symbol);
# ### $commodity
# unless ($commodity) {
# _errormsg (\%quotes, [$symbol], 'No such symbol');
# next;
# }
# my $this_list = [ $symbol ];
#
# }
# split into symbols Ixxxx and AJxxx which are aquote and the rest wquote
my @aq_keys;
my %aq_symbol_list;
foreach my $symbol (@symbol_list) {
my $key = ($symbol =~ /^[AI]/ ? 'a' : 'w');
unless ($aq_symbol_list{$key}) {
push @aq_keys, $key;
}
push @{$aq_symbol_list{$key}}, $symbol;
}
### @aq_keys
### %aq_symbol_list
foreach my $aq (@aq_keys) {
require HTTP::Request;
my $req = HTTP::Request->new ('GET', $aq_url{$aq});
$ua->prepare_request ($req);
$req->accept_decodable; # we use decoded_content() below
$req->user_agent (__PACKAGE__."/$VERSION " . $req->user_agent);
### req: $req->as_string
my $resp = $ua->request ($req);
resp_to_quotes ($fq, $resp, \%quotes, $aq_symbol_list{$aq});
}
return wantarray() ? %quotes : \%quotes;
}
sub symbol_to_commodity {
my ($str) = @_;
$str =~ s/[A-Z][0-9]+$//;
return $str;
}
my %aquote_name_to_commodity
= ('PIT NCI' => 'IC',
'NCI' => 'IC',
'HRWI' => 'IH',
'HRSI' => 'IP',
'SRWI' => 'IW',
'NSI' => 'IS',
# Apple Juice gone in 2019.
# 'AJC' => 'AJ',
);
my %month_code_to_month = ('F' => 1,
'G' => 2,
'H' => 3,
'J' => 4,
'K' => 5,
'M' => 6,
'N' => 7,
'Q' => 8,
'U' => 9,
'V' => 10,
'X' => 11,
'Z' => 12);
my @month_to_month_code
= (undef, 'F','G','H','J','K','M','N','Q','U','V','X','Z');
my %month_name_to_number = ('jan' => 1,
'feb' => 2,
'mar' => 3,
'apr' => 4,
'may' => 5,
'jun' => 6,
'jul' => 7,
'aug' => 8,
'sep' => 9,
'oct' => 10,
'nov' => 11,
'dec' => 12);
sub _name_to_NSCM {
my ($name) = @_;
### _name_to_NSCM(): $name
my ($symbol, $commodity, $month, $y);
lib/Finance/Quote/MGEX.pm view on Meta::CPAN
|| return; # if unrecognised
$symbol = $commodity
. $month_to_month_code[$month]
. $y; # two digit year
} elsif ($name =~ m{\((([A-Z]+)([A-Z])([0-9]+))\)}) {
# wquotes_js.js name like
# "MGEX (MWN9)"
# "KCBT (KEZ9)"
#
$name = undef;
$symbol = $1;
$commodity = $2;
my $month_code = $3;
$month = $month_code_to_month{$month_code}
|| return; # if unrecognised
$y = $4;
} else {
return;
}
my $year = _y_to_year($y);
### $year
my $contract_month = sprintf ('%04d-%02d-01', $year, $month);
return ($name, $symbol, $commodity, $contract_month);
}
sub _y_to_year {
my ($y) = @_;
my $modulus = (length($y) == 1 ? 10 : 100);
my $half = $modulus / 2;
my $base = _this_year() - $half;
return $base + (($y - $base) % $modulus);
}
sub _this_year {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = gmtime(time());
return $year + 1900;
}
# store to hashref $quotes all the $symbol_list symbols picked out of a
# HTTP::Response in $resp
sub resp_to_quotes {
my ($fq, $resp, $quotes, $symbol_list) = @_;
my %want_symbol;
@want_symbol{@$symbol_list} = (); # hash slice
my %seen_symbol;
foreach my $symbol (@$symbol_list) {
$quotes->{$symbol,'method'} = 'mgex';
$quotes->{$symbol,'source'} = __PACKAGE__;
$quotes->{$symbol,'success'} = 0; # false if not in returned
}
if (! $resp->is_success) {
_errormsg ($quotes, $symbol_list, $resp->status_line);
return;
}
my $content = $resp->decoded_content (raise_error => 1);
$content = _javascript_document_write ($content);
### $content
$content =~ s/ / /g;
my $page_date;
if ($content =~ /for ([a-zA-Z]+ [0-9]{1,2}, [0-9]{4})/) {
$page_date = $1;
### $page_date
}
require HTML::TableExtract;
my $te = HTML::TableExtract->new
(headers => [ qr/Contract/i,
qr/Last/i,
qr/Change/i,
qr/Bid/,
qr/Ask/i,
qr/Open/i,
qr/High/,
qr/Low/i,
qr/Settle/i,
qr/Time/i ]);
$te->parse ($content);
if (! $te->tables) {
_errormsg ($quotes, $symbol_list, 'table not matched');
return;
}
foreach my $row ($te->rows) {
### $row
if (! defined $row->[0]) {
### undef empty row, skip ...
next;
}
my ($orig_name, $last, $change, $bid, $ask, $open, $high, $low,
$prev, $last_time)
= map { my $str = $_;
$str =~ s/^\s+//;
$str =~ s/\s+$//;
$str } @$row;
my ($name, $symbol, $commodity, $contract_month)
= _name_to_NSCM ($orig_name);
if (! defined $symbol) {
### unrecognised row: $orig_name
next;
}
### $name
### $symbol
### $commodity
### $contract_month
if (! exists $want_symbol{$symbol}) {
### not wanted: $symbol
next;
}
# "5 x 195-2" or whatever for count of bid/offers
# seen in 2006, but maybe no longer generated
( run in 1.583 second using v1.01-cache-2.11-cpan-a49fcb8fa48 )