# # Copyright (C) 1998, Dj Padzensky # Copyright (C) 1998, 1999 Linas Vepstas # Copyright (C) 2000, Yannick LE NY # Copyright (C) 2000, Paul Fenwick # Copyright (C) 2000, Brent Neal # Copyright (C) 2013, Manoj Kumar # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA # 02111-1307, USA # # This code derived from Padzensky's work on package Finance::YahooQuote, # but extends its capabilites to encompas a greater number of data sources. # # This code was developed as part of GnuCash package Finance::Quote::IciciDirect; require 5.005; use strict; use warnings; use HTML::TreeBuilder; use Finance::Quote::SymbolTranslation qw(symbol_translation); our ($VERSION, $MAIN_URL, $URL); $VERSION = '1.18'; $MAIN_URL = 'http://content.icicidirect.com'; $URL = $MAIN_URL . '/newsiteContent/includes/nsebsequotes.asp?icicicode='; sub methods { return ( icici_direct => \&icici_direct, nse_india => \&icici_direct_nse, bse_india => \&icici_direct_bse, india_shares => \&icici_direct ); } { my @labels = qw/currency date isodate last method success symbol exchange/; sub labels { return ( icici_direct => \@labels, nse_india => \@labels, bse_india => \@labels, india_shares => \@labels ); } } sub icici_direct { icici_direct_common(@_, 'icici_direct'); } sub icici_direct_nse { icici_direct_common(@_, 'icici_direct_nse'); } sub icici_direct_bse { icici_direct_common(@_, 'icici_direct_bse'); } sub icici_direct_common { my $quoter = shift; my $method = pop; my @symbols = @_; return unless @symbols; my (%info, $ref_trans_1); my ($ua, $url, $response); my ($nse, $bse); $ua = $quoter->user_agent; $nse = ($method eq 'icici_direct_bse') ? 0 : 1; $bse = ($method eq 'icici_direct_nse') ? 0 : 1; ($ref_trans_1, undef) = symbol_translation('icici_direct', \@symbols, 1); foreach my $symbol (@symbols) { $url = $URL . $ref_trans_1->{uc($symbol)}; $info{$symbol, 'method'} = 'icici_direct'; $info{$symbol, 'success'} = 0; my $response = $ua->get($url); if ($response->is_success) { my $root = HTML::TreeBuilder->new(); $root->utf8_mode(1); # avoid warning Parsing of undecoded UTF-8 will give garbage when decoding entities at $root->parse_content($response->content); my %t_info = extract_icici_direct_info($root, $nse, $bse); if (exists $t_info{last} && exists $t_info{date}) { $info{$symbol, 'symbol'} = $ref_trans_1->{uc($symbol)}; $info{$symbol, 'currency'} = 'INR'; $info{$symbol, 'last'} = $t_info{last}; $info{$symbol, 'exchange'} = $t_info{exchange}; $quoter->store_date(\%info, $symbol, {eurodate => $t_info{date}}); $info{$symbol, 'success'} = 1; } else { $info{$symbol, 'errormsg'} = 'Stock lookup failed'; } $root->delete(); } else { $info{$symbol, 'errormsg'} = 'Stock lookup failed'; } } return wantarray ? %info : \%info; } sub extract_info { my $root = shift; my @search = ( {search => '^\s*Date\s*&\s*Time\s*$', label => 'date'}, {search => '^\s*Current\s*$', label => 'last'}, {search => '^\s*Open\s*$', label => 'open'}, {search => '^\s*Change\s*$', label => 'net'}, {search => '^\s*High\s*$', label => 'high'}, {search => '^\s*%\s*Change\s*$', label => 'p_change'}, {search => '^\s*Low\s*$', label => 'low'}, {search => '^\s*Prev\s*Close\s*$', label => 'close'}, {search => '^\s*52\s*Week\s*high\s*$', label => 'y_high'}, {search => '^\s*Volume\s*$', label => 'volume'}, {search => '^\s*52\s*Week\s*Low\s*$', label => 'y_low'}, {search => '^\s*(NSE|BSE)\s*Code\s*$', label => 'code'}, ); my %info; my $element; foreach (@search) { my $search = $_->{search}; $element = $root->look_down('_tag', 'td', sub { $_[0]->as_text() =~ m/$search/i; } ); if ($element && $element->right()) { $info{$_->{label}} = $element->right()->as_text(); } } if (exists $info{date} && $info{date} =~ m/(\S+)\s+(\S+)/) { $info{date} = $1; $info{time} = $2; } foreach ('close', 'high', 'last', 'low', 'net', 'open', 'p_change', 'volume', 'y_high', 'y_low') { if (exists $info{$_}) { $info{$_} =~ s/,//g; } } return(%info); } sub date_ok { my $date = shift; return 0 unless $date =~ m/(\d+)-(\w+)-(\d+)/; my ($month1, $year1, $month2, $year2); my %months = (jan => 1, feb => 2, mar => 3, apr => 4, may => 5, jun => 6, jul => 7, aug => 8, sep => 9, oct =>10, nov =>11, dec =>12); ($month1, $year1) = ($2, $3); if ($month1 !~ m/\d/) { $month1 = $months{lc($month1)}; } $month1--; (undef, undef, undef, undef, $month2, $year2, undef, undef, undef) = localtime; $year2 += 1900; if (abs(($year1 * 12 + $month1) - ($year2 * 12 + $month2)) > 3) { # date too old return 0; } return 1; } sub extract_icici_direct_info { my $root = shift; my $nse = shift; my $bse = shift; my ($element, %info); if ($nse) { %info = (); $element = $root->look_down('_tag', 'td', sub { $_[0]->as_text() =~ m/^\s*NSE Code\s*$/; } ); if ($element && $element->parent() && $element->parent()->parent()) { %info = extract_info($element->parent()->parent()); $info{exchange} = 'NSE'; } if ($info{last} && $info{date} && date_ok($info{date})) { return(%info); } } if ($bse) { %info = (); $element = $root->look_down('_tag', 'td', sub { $_[0]->as_text() =~ m/^\s*BSE Code\s*$/; } ); if ($element && $element->parent() && $element->parent()->parent()) { %info = extract_info($element->parent()->parent()); $info{exchange} = 'BSE'; } if ($info{last} && $info{date} && date_ok($info{date})) { return(%info); } } return(); } 1; =head1 NAME Finance::Quote::IciciDirect - Fetch quotes from ICICI Direct http://www.icicidirect.com =head1 SYNOPSIS use Finance::Quote; $q = Finance::Quote->new(); %info = $q->fetch('india_shares', 'TCS'); # Failover to other methods ok. %info = $q->fetch('nse_india', 'TCS'); # Failover to other methods ok for NSE shares. %info = $q->fetch('bse_india', 'TCS'); # Failover to other methods ok for BSE shares. %info = $q->fetch('icici_direct', 'TCS'); # Use this module only. =head1 DESCRIPTION This module obtains information about india shares from ICICI Direct web site http://www.icicidirect.com. This module uses Finance::Quote::SymbolTranslation for symbol translation. Source name for this purpose is icici_direct. =head1 LABELS RETURNED this source returns following lables on success: currency - INR date - date in US (mm/dd/yyyy) format exchange - NSE / BSE isodate - date in ISO (yyyy-mm-dd) format last - closing price in INR method - icici_direct symbol - ICICI Direct code success - 0 = failure / 1 = success errormsg - only if success is 0 =head1 SEE ALSO ICICI Direct web site http://www.icicidirect.com. Finance::Quote, Finance::Quote::SymbolTranslation =cut