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
|
|
2690
|
use strict; |
|
5
|
|
|
|
|
28
|
|
|
5
|
|
|
|
|
180
|
|
11
|
5
|
|
|
5
|
|
39
|
use POSIX qw(strftime); |
|
5
|
|
|
|
|
22
|
|
|
5
|
|
|
|
|
50
|
|
12
|
5
|
|
|
5
|
|
443
|
use IO::Uncompress::Unzip qw(unzip $UnzipError); |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
700
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
our $VERSION = '1.57_03'; # TRIAL VERSION |
15
|
|
|
|
|
|
|
|
16
|
5
|
|
|
5
|
|
59
|
use vars qw($NSE_MAIN_URL $NSE_URL); |
|
5
|
|
|
|
|
251
|
|
|
5
|
|
|
|
|
4701
|
|
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
|
206
|
sub methods { return ( 'india' => \&nseindia, |
25
|
|
|
|
|
|
|
'nseindia' => \&nseindia ); } |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub labels { |
28
|
5
|
|
|
5
|
0
|
133
|
my @labels = qw/close last high low open prevclose exchange/; |
29
|
|
|
|
|
|
|
return ( |
30
|
5
|
|
|
|
|
24
|
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 |