File Coverage

blib/lib/Finance/Quote/NSEIndia.pm
Criterion Covered Total %
statement 15 78 19.2
branch 0 26 0.0
condition 0 6 0.0
subroutine 6 7 85.7
pod 0 3 0.0
total 21 120 17.5


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             #
4             # Initial version based on IndiaMutual.pm
5             #
6              
7             package Finance::Quote::NSEIndia;
8             require 5.010;
9              
10 5     5   2550 use strict;
  5         13  
  5         221  
11 5     5   40 use POSIX qw(strftime);
  5         9  
  5         84  
12 5     5   495 use IO::Uncompress::Unzip qw(unzip $UnzipError);
  5         14  
  5         712  
13              
14             our $VERSION = '1.58'; # VERSION
15              
16 5     5   45 use vars qw($NSE_MAIN_URL $NSE_URL);
  5         10  
  5         4823  
17             $NSE_MAIN_URL = "https://www.nseindia.com";
18             $NSE_URL = "https://archives.nseindia.com";
19              
20             my $cachedir = $ENV{TMPDIR} // $ENV{TEMP} // '/tmp/';
21             my $NSE_ZIP = $cachedir.'nseindia.zip';
22             my $NSE_CSV = $cachedir.'nseindia.csv';
23              
24 5     5 0 26 sub methods { return ( 'india' => \&nseindia,
25             'nseindia' => \&nseindia ); }
26              
27             sub labels {
28 5     5 0 17 my @labels = qw/close last high low open prevclose exchange/;
29             return (
30 5         17 india => \@labels,
31             nseindia => \@labels
32             );
33             }
34              
35             sub nseindia {
36 0     0 0   my $quoter = shift;
37 0           my @symbols = @_;
38 0 0         return unless @symbols;
39              
40 0           my (%info, $errormsg, $fh, $ua, $url, $reply);
41              
42 0           $ua = $quoter->user_agent;
43             # Disable redirects - server redirects instead of 404.
44 0           $ua->requests_redirectable([]);
45              
46 0           my %mnames = ('01' => 'JAN', '02' => 'FEB', '03' => 'MAR', '04' => 'APR', '05' => 'MAY', '06' => 'JUN',
47             '07' => 'JUL', '08' => 'AUG', '09' => 'SEP', '10' => 'OCT', '11' => 'NOV', '12' => 'DEC');
48             # Try to fetch last 10 days
49 0           for (my ($days, $now) = (0, time()); $days < 10; $days++) {
50             # Ex: https://archives.nseindia.com/content/historical/EQUITIES/2020/APR/cm23APR2020bhav.csv.zip
51 0           my @lt = localtime($now - $days*24*60*60);
52 0           my ($day, $month, $year, $url);
53 0           $day = strftime "%d", @lt;
54 0           $month = $mnames{strftime "%m", @lt}; # Can't use %b as it's locale dependent.
55 0           $year = strftime "%Y", @lt;
56 0           $url = $NSE_URL . "/content/historical/EQUITIES/$year/$month/cm$day$month${year}bhav.csv.zip";
57 0           $reply = $ua->mirror($url, $NSE_ZIP);
58             # print "$url", $reply->is_success, $reply->status_line, "\n"; #DEBUG
59 0 0 0       if ($reply->is_success or $reply->code == 304) {
60 0           last;
61             }
62             }
63              
64 0 0 0       if (!$reply->is_success and $reply->code != 304) {
65 0           $errormsg = "HTTP failure : " . $reply->status_line;
66             }
67              
68 0 0         if (!$errormsg) {
69 0 0         if (! unzip $NSE_ZIP => $NSE_CSV) {
70 0           $errormsg = "Unzip error : $UnzipError";
71             }
72             }
73              
74 0 0         if (!$errormsg) {
75 0 0         if (! open $fh, '<', $NSE_CSV) {
76 0           $errormsg = "CSV open error: $!";
77             }
78             }
79              
80 0 0         if ($errormsg) {
81 0           foreach my $symbol (@symbols) {
82 0           $info{$symbol, "success"} = 0;
83 0           $info{$symbol, "errormsg"} = $errormsg;
84             }
85 0 0         return wantarray() ? %info : \%info;
86             }
87              
88             # Create a hash of all stocks requested
89 0           my %symbolhash;
90 0           foreach my $symbol (@symbols)
91             {
92 0           $symbolhash{$symbol} = 0;
93             }
94 0           my $csvhead;
95             my @headhash;
96              
97             # SYMBOL,SERIES,OPEN,HIGH,LOW,CLOSE,LAST,PREVCLOSE,TOTTRDQTY,TOTTRDVAL,TIMESTAMP,TOTALTRADES,ISIN,
98 0           $csvhead = <$fh>;
99 0           chomp $csvhead;
100 0           @headhash = split /\s*,s*/, $csvhead;
101 0           while (<$fh>) {
102 0           my @data = split /\s*,s*/;
103 0           my %datahash;
104             my $symbol;
105 0           @datahash{@headhash} = @data;
106 0 0         if (exists $symbolhash{$datahash{"SYMBOL"}}) {
    0          
107 0           $symbol = $datahash{"SYMBOL"};
108             }
109             elsif(exists $symbolhash{$datahash{"ISIN"}}) {
110 0           $symbol = $datahash{"ISIN"};
111             }
112             else {
113 0           next;
114             }
115 0           $info{$symbol, 'symbol'} = $symbol;
116 0           $info{$symbol, 'close'} = $datahash{"CLOSE"};
117 0           $info{$symbol, 'last'} = $datahash{"LAST"};
118 0           $info{$symbol, 'high'} = $datahash{"HIGH"};
119 0           $info{$symbol, 'low'} = $datahash{"LOW"};
120 0           $info{$symbol, 'open'} = $datahash{"OPEN"};
121 0           $info{$symbol, 'prevclose'} = $datahash{"PREVCLOSE"};
122 0           $quoter->store_date(\%info, $symbol, {eurodate => $datahash{"TIMESTAMP"}});
123 0           $info{$symbol, 'method'} = 'nseindia';
124 0           $info{$symbol, 'currency'} = 'INR';
125 0           $info{$symbol, 'exchange'} = 'NSE';
126 0           $info{$symbol, 'success'} = 1;
127             }
128 0           close($fh);
129              
130 0           foreach my $symbol (@symbols) {
131 0 0         unless (exists $info{$symbol, 'success'}) {
132 0           $info{$symbol, 'success'} = 0;
133 0           $info{$symbol, 'errormsg'} = 'Stock not found on NSE.';
134             }
135             }
136              
137 0 0         return wantarray ? %info : \%info;
138             }
139              
140              
141             1;
142              
143              
144             =head1 NAME
145              
146             Finance::Quote::NSEIndia - Obtain quotes from NSE India.
147              
148             =head1 SYNOPSIS
149              
150             use Finance::Quote;
151              
152             $q = Finance::Quote->new();
153              
154             %info = $q->fetch('nseindia', 'TCS'); # Only query NSE.
155             %info = $q->fetch('india', 'TCS'); # Failover to other sources OK.
156              
157             =head1 DESCRIPTION
158              
159             This module obtains information about shares listed on the National Stock Exchange of India Ltd.
160             Source is the daily bhav copy (zipped CSV).
161              
162             This module provides both the "nseindia" and "india" fetch methods. Please use the "india" fetch method if you wish to have failover with other sources for Indian stocks (such as BSE).
163              
164             =head1 LABELS RETURNED
165              
166             The following labels may be returned by Finance::Quote::NSEIndia:
167             close, last, high, low, open, prevclose, exchange
168              
169             =head1 SEE ALSO
170              
171             National Stock Exchange of India Ltd., http://www.nseindia.com/
172              
173             =cut